How do I handle a nil value for Plug.Upload in params?
Opened this issue · 1 comments
- Elixir 1.2
- Phoenix 1.2.1
- arc: 0.6.0
- arc_ecto 0.5.0
According to the Phoenix documentation, if no file is selected, Plug.Upload
will not be present in the params map.
Finally, notice that when there is no data from the file input, we get neither the "photo" key nor a Plug.Upload struct. Here are the user_params from the log.
So if you submit a blank form, params[:user]
will be nil
. For example:
<%= form_for @changeset, @action, [multipart: true], fn f -> %>
<%= file_input f, :avatar %>
<%= submit "Submit" %>
<% end %>
Notice the absence of the "user" key.
%{"_csrf_token" => "...", "_method" => "put", "_utf8" => "✓"}
Which raises an error in the controller.
bad request to App.Account.AvatarController.update, no matching action clause to process request
def update(conn, %{"user" => user_params}, current_user) do
changeset = User.avatar_changeset(current_user, user_params)
case Repo.update(changeset) do
{:ok, _} ->
redirect(conn, to: current_user_avatar_path(conn, :edit))
{:error, changeset} ->
render(conn, :edit, changeset: changeset, user: current_user)
end
We can hack around the error by including a hidden field in the form, forcing params[:user]
to exist.
<%= hidden_input f, :id %>
But Plug.Upload
will still be missing from the params. Which means the changeset will be valid. Notice changes
being an empty map.
#Ecto.Changeset<action: nil, changes: %{}, errors: [], data: #App.User<>,
valid?: true>
So, my questions are this:
- What's the point of
|> validate_required([:avatar])
given thatPlug.Upload
is only present with file data? To reach this point in the changeset, a field must be present. It seems redundant then to validate for presence. - How do we validate the presence of
avatar
?
Here's my user schema:
defmodule App.User do
use App.Web, :model
use Arc.Ecto.Schema
schema "users" do
# ...
field :avatar, App.AvatarUploader.Type
end
def avatar_changeset(struct, params \\ %{}) do
struct
|> cast(params, [:avatar])
|> cast_attachments(params, [:avatar])
|> validate_required([:avatar])
end
Am I missing something?
Maybe the quickiest way is to pattern match on the update
function in controller where you check that params
doesn't contain the "user"
key.