Copying errors into the form during `inputs_for`?

Why does Phoenix.HTML.FormData.Ecto.Changeset.form_for_errors/1 only copy errors into the form when the action is set to :insert, :update, :delete, or :replace? I understand not copying the errors on :ignore, but the nil clause is interesting to me.

A little explanation of what I’m trying to do:

defmodule MyApp.MyDomain.MySchema do
  embedded_schema do
    embeds_one :foo, Foo
    embeds_one :bar, Bar

  @doc """
  This used in my Phoenix controller as shown below.
  def changeset(model, attrs) do
    |> cast(attrs, [])
    |> cast_embed(:foo)
    |> cast_embed(:bar)
<%= form_for @changeset, my_path(@conn, :create), fn form -> %>
  <%= inputs_for form, :foo, fn foo_form -> %>
  <% end %>
  <%= inputs_for form, :bar, fn bar_form -> %>
  <% end %>
<% end %>

This schema is basically a compatibility layer that gets transformed into an Ecto.Multi for insertion. Since Ecto.Multi has no implementation for Phoenix.HTML.FormData, this is the way I chose to go about working the problem.

Because the changeset I’m displaying is based on this embedded schema, the :action for the changeset is set to nil (I think … that’s how I understand it anyway). As such, form_for_errors/1 ignores the errors that are on the nested embedded schemas.

Why isn’t form_for_errors/1 written like this?

defp form_for_errors(%{action: :ignore}), do: []
defp form_for_errors(%{errors: errors}), do: errors

This implementation breaks five different tests, so it’s clear that we mean to ignore the errors when %{action: nil}.

Why is this? Is there some other way that I should approach the problem?

1 Like