A call to inputs_for
that uses :prepend
seems to skip the prepended value when the containing form has errors (that is: was created from a changeset with errors). Is this a bug?
Here’s what a form looks like for an animal with no “service gaps”:
This form represents an animal that has_many
service gaps. In this case, it has none.
The code that produced the form’s HTML looks like this:
form_for @changeset, "/not-used", fn f ->
...
inputs_for(f, :service_gaps, [prepend: [%ServiceGap{}]], fn gap_f -> ...
The form itself looks like this:
%Phoenix.HTML.Form{
data: %Crit.Usables.Schemas.Animal{...
service_gaps: [],...
},
errors: [],
}
All is OK in this case.
Now suppose I submit the form with an error in one of the animal fields. In this case, I try to rename it to an already-existing name. The resulting changeset gets fed to form_for
and the form looks like this:
%Phoenix.HTML.Form{
data: %Crit.Usables.Schemas.Animal{...
service_gaps: [],...
},
errors: [
name: {"has already been taken",
[constraint: :unique, constraint_name: "unique_available_names"]}
],
}
In this case, the function argument to inputs_for
is not called for the :prepend
value. Since there are no actual service gaps, the function is never called. That means:
- If a user chooses to edit an animal, she can add a service gap and change properties of the animal.
- But, if she makes a mistake changing an animal’s properties, the ability to add a new service gap mysteriously disappears.
In the case where the animal already has service gaps, the non-prepend values for inputs_for
are still processed. For example, here’s the initial form for an animal with a single service gap:
The same mistake (picking a new name the same as an existing name) produces this form:
(The “Add a gap” heading is wrong because the code assumes the first set of fields will be for the prepended empty Animal
. But it’s not, because the empty Animal
got skipped.)
So: it seems that, in the presence of an error in the top-level Form
structure, inputs_for
ignores specifically the prepended value used to create a new “assoc” value. But it processes other values.