Phoenix.HTML.Form has two errors fields when validating?

Hi -
I’m running Phoenix 1.2.1 and Elixir 1.3.4 and having some trouble getting simple form validation to work. I’m following along in the Programming Phoenix guide and have this create function in my code

  def create(conn, %{"user" => user_params}) do
changeset = User.changeset(%User{}, user_params)
case Repo.insert(changeset) do
  {:ok, user} ->
      conn
      |> put_flash(:info, "#{user.first_name} #{user.last_name} successfully registered!   Check for a confirmation email in your inbox.")
      |> redirect(to: user_path(conn, :show, user.id))
  {:error, changeset} ->
      render(conn, "new.html", changeset: changeset, title: "Register")
end

end

When I post the form I get this when I dump out the “form” that is passed into error_tag function

[debug] %Phoenix.HTML.Form{data: %{}, errors: [], hidden: [], id: "user", impl: Phoenix.HTML.FormData.Plug.Conn, index: nil, name: "user", options: [class: "settings-form"], params: %{"email" => "", "first_name" => "", "last_name" => "", "password" => "", "password_confirmation" => ""}, source: %Plug.Conn{adapter: {Plug.Adapters.Cowboy.Conn, :...}, assigns: %{changeset: #Ecto.Changeset<action: :insert, changes: %{username: ""}, errors: [first_name: {"can't be blank", [validation: :required]}, last_name: {"can't be blank", [validation: :required]}, email: {"can't be blank", [validation: :required]}, password: {"can't be blank", [validation: :required]}, password_confirmation: {"can't be blank", [validation: :required]}], data: #Go2sci.User<>, valid?: false>, layout: {Go2sci.LayoutView, "app.html"}, title: "Register"}, .....

So when i dump out form.errors in the error_tag function it’s always [] but as you can see the form object has both an errors = [] and another one that says
errors: [first_name: {“can’t be blank”, [validation: :required]}, last_name: {“can’t be blank”, [validation: :required]}, email: {“can’t be blank”, [validation: :required]}, password: {“can’t be blank”, [validation: :required]}, password_confirmation: {“can’t be blank”, [validation: :required]}]

Not sure what’s going on? I saw this issue which briefly discusses the problem but it made it seem like it was fixed and it was from almost a year ago.

Thanks for any help

So first let’s format that output:

%Phoenix.HTML.Form{
  data: %{},
  errors: [],
  hidden: [],
  id: "user",
  impl: Phoenix.HTML.FormData.Plug.Conn,
  index: nil,
  name: "user",
  options: [class: "settings-form"],
  params: %{
    "email" => "",
    "first_name" => "",
    "last_name" => "",
    "password" => "",
    "password_confirmation" => ""
    },
  source: %Plug.Conn{
    adapter: {Plug.Adapters.Cowboy.Conn, :...},
    assigns: %{
      changeset: #Ecto.Changeset<
        action: :insert,
        changes: %{username: ""},
        errors: [
          first_name: {"can't be blank", [validation: :required]},
          last_name: {"can't be blank", [validation: :required]},
          email: {"can't be blank", [validation: :required]},
          password: {"can't be blank", [validation: :required]},
          password_confirmation: {"can't be blank", [validation: :required]}
          ],
        data: #Go2sci.User<>,
        valid?: false
        >,
      layout: {Go2sci.LayoutView, "app.html"},
      title: "Register"
    },
    ...

So, looking at this it is now obvious that the %Phoenix.HTML.Form{} only has one errors entry, and it is indeed an empty list. The form holds information from where this information came from in its source key, thus being the same %Plug.Conn{} that is passed everywhere in your pipeline. Your %Plug.Conn{} has a key called assigns that anything, you, a plug, whatever, can store temporary information on that may be useful later on in the pipeline, in this assigns there is a user/plug-added key called errors, this one is entirely different from the errors on the %Phoenix.HTML.Form{} of course, since different objects, however this key’s value appears to have the information you are missing.

Now, this says two things to me:

  1. A put_assign/3 is called somewhere in your pipeline that is adding the :errors key, why? No clue.
  2. You are giving the form your plug instead of your changeset, you probably want to give it your changeset, not your plug. :slight_smile:

EDIT: Also, the linked github issue is entirely unrelated. :slight_smile:

thanks OvermindDL1! I didn’t see that source being a map…
The problem was as you suspected my HTML form in the template was jacked up - I had form_for @conn instead of @changeset. That’s what I get for copy/pasting from an ePub book …

Thanks again for the detailed response!

1 Like