No matching clause - when sending MULTIPART Data to Phoenix APi

I know it is something really stupid there, but I am new to elixir and phoenix and can`t figure it out myself.

I am uploading picture from my Ember.js data client to Phoenix backend with Arc. Everything works fine, until I send some more data with a picture(profile_id) to the backend. I see the data I need there, but I don`t do pattern matching in my Create as I should there - I suppose it is the core of the problem.

It can of course be anything with JSON vs MULTIPART and so on, but I don`t see it from the error it gives me - I see data formated well…

Please, could you help me and point me to the right direction? Thank you very much guys. And sorry for the english.

Here is my controller and error:

controller:

defmodule MyApp.PhotoController do
use MyApp.Web, :controller
import Ecto.Query

alias MyApp.Photo
alias MyApp.Profile

def index(conn, %{“profile_id” => profile_id}) do
photos = Photo
|> where(profile_id: ^profile_id)
|> Repo.all

render(conn, "index.json", photos: photos)

end

def create(conn, %{“photo” => photo_params, “profile” => profile_id}) do
profile = Repo.get!(Profile, profile_id)
changeset =
profile
|> build_assoc(:photos)
|> Photo.changeset(photo_params)

case Repo.insert(changeset) do
 {:ok, photo} ->
   conn
   .....
 {:error, changeset} ->
   conn
   .....

end
end
end

error:

[debug] Processing by MyApp.PhotoController.create/2
Parameters: %{“photo” => %{“image” => %Plug.Upload{content_type: “image/jpeg”, filename: “6.jpg”, path: “/var/folders/xz/kjfbrp6s0sz45r5z8dyfb5z00000gn/T//plug-1479/multipart-755482-738922-1”}, “profile” => “1”}}
Pipelines: [:api]
[info] Sent 400 in 9ms
[debug] ** (Phoenix.ActionClauseError) bad request to MyApp.PhotoController.create, no matching action clause to process request
(my_app) web/controllers/photo_controller.ex:16: MyApp.PhotoController.create(%Plug.Conn{adapter: {Plug.Adapters.Cowboy.Conn, :…}, assigns: %{}, before_send: [#Function<1.74471148/1 in Plug.Logger.call/2>], body_params: %{“photo” => %{“image” => %Plug.Upload{content_type: “image/jpeg”, filename: “6.jpg”, path: “/var/folders/xz/kjfbrp6s0sz45r5z8dyfb5z00000gn/T//plug-1479/multipart-755482-738922-1”}, “profile” => “1”}}, cookies: %Plug.Conn.Unfetched{aspect: :cookies}, halted: false, host: “localhost”, method: “POST”, owner: #PID<0.790.0>, params: %{“photo” => %{“image” => %Plug.Upload{content_type: “image/jpeg”, filename: “6.jpg”, path: “/var/folders/xz/kjfbrp6s0sz45r5z8dyfb5z00000gn/T//plug-1479/multipart-755482-738922-1”}, “profile” => “1”}}, path_info: [“api”, “photos”], peer: {{127, 0, 0, 1}, 51827}, port: 4000, private: %{MyApp.Router => {, %{}}, :phoenix_action => :create, :phoenix_controller => MyApp.PhotoController, :phoenix_endpoint => MyApp.Endpoint, :phoenix_format => “html”, :phoenix_layout => {MyApp.LayoutView, :app}, :phoenix_pipelines => [:api], :phoenix_route => #Function<1.49344645/1 in MyApp.Router.match_route/4>, :phoenix_router => MyApp.Router, :phoenix_view => MyApp.PhotoView, :plug_session_fetch => #Function<1.82590416/1 in Plug.Session.fetch_session/1>}, query_params: %{}, query_string: “”, remote_ip: {127, 0, 0, 1}, req_cookies: %Plug.Conn.Unfetched{aspect: :cookies}, req_headers: [{“host”, “localhost:4000”}, {“connection”, “keep-alive”}, {“content-length”, “1220930”}, {“accept”, “/”}, {“origin”, “http://localhost:4200”}, {“user-agent”, “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36”}, {“content-type”, “multipart/form-data; boundary=----WebKitFormBoundaryFkoyud6Q4AAjieZ3”}, {“referer”, “http://localhost:4200/profile/2”}, {“accept-encoding”, “gzip, deflate, br”}, {“accept-language”, “cs-CZ,cs;q=0.8,en;q=0.6,sk;q=0.4,pl;q=0.2”}], request_path: “/api/photos”, resp_body: nil, resp_cookies: %{}, resp_headers: [{“cache-control”, “max-age=0, private, must-revalidate”}, {“x-request-id”, “ucq2f4rekclsh328nt5g3vc3crun02fu”}, {“access-control-allow-origin”, “*”}, {“access-control-expose-headers”, “”}, {“access-control-allow-credentials”, “true”}], scheme: :http, script_name: , secret_key_base: “oP7dum2H51kSnbgWblMqQ19g6Y59hnFmJyAuyl12osAVKs1C1ZGl9cB6X7OJGU+f”, state: :unset, status: nil}, %{“photo” => %{“image” => %Plug.Upload{content_type: “image/jpeg”, filename: “6.jpg”, path: “/var/folders/xz/kjfbrp6s0sz45r5z8dyfb5z00000gn/T//plug-1479/multipart-755482-738922-1”}, “profile” => “1”}})
(my_app) web/controllers/photo_controller.ex:1: MyApp.PhotoController.action/2
(my_app) web/controllers/photo_controller.ex:1: MyApp.PhotoController.phoenix_controller_pipeline/2
(my_app) lib/my_app/endpoint.ex:1: MyApp.Endpoint.instrument/4
(my_app) lib/phoenix/router.ex:261: MyApp.Router.dispatch/2
(my_app) web/router.ex:1: MyApp.Router.do_call/2
(my_app) lib/my_app/endpoint.ex:1: MyApp.Endpoint.phoenix_pipeline/1
(my_app) lib/plug/debugger.ex:123: MyApp.Endpoint.“call (overridable 3)”/2
(my_app) lib/my_app/endpoint.ex:1: MyApp.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4

It looks like your parameters are actually structured like this:

%{"photo" => %{"image" => %Plug.Upload{}, "profile" => integer}}

So you just need to change the function parameters to:
create(conn, %{"photo" => %{"image" => photo_params, "profile" => profile_id}})

hope this helps!

1 Like

Thanks. I will try it. The strange thing(for me) was that when I remove “profile” => profile_id than it saves well and image is uploaded.

Well. Stupid one. I see it there now :smiley: I was looking for this kind of mistake really a long time, but I didn’t see it there. Thank you for helping me :smiley:

1 Like

I’m currently building a Ember / Phoenix app which requires file upload, you mentioned Arc for Phoenix, what are you using for Ember? I’m considering ember-plupload but I’m open for suggestions. The other part of the equation is I would like to stick with GraphQL (ember-apollo-client / Absinthe) throughout but I haven’t even begun to look into file uploads with it.

1 Like