Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I handle a nil value for Plug.Upload in params? #55

Open
abitdodgy opened this issue Jan 3, 2017 · 1 comment
Open

How do I handle a nil value for Plug.Upload in params? #55

abitdodgy opened this issue Jan 3, 2017 · 1 comment

Comments

@abitdodgy
Copy link

abitdodgy commented Jan 3, 2017

  • 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:

  1. What's the point of |> validate_required([:avatar]) given that Plug.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.
  2. 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?

@andreapavoni
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants