polymorphic_embed
polymorphic_embed copied to clipboard
During form submission, embedded arrays only contain the last entry
I currently have a schema with this shape:
schema "ClientInstance" do
field :ext_ref, Ecto.UUID
field :notes, :string
embeds_one :query, EmbeddedSchema.ClientInstance
timestamps()
end
with the embedded schema as follows:
embedded_schema do
field :includes, {:array, :string}
field :queries, {:array, PolymorphicEmbed},
types: [
queryquery: [module: Query, identify_by_fields: [:bar]],
...
],
on_type_not_found: :ignore,
on_replace: :delete
end
Given a changeset like so:
#Ecto.Changeset<
action: nil,
changes: %{
ext_ref: "6201d502-6422-4b49-9849-e07fd4fe5899",
notes: "Misbehaving Tester",
query: #Ecto.Changeset<
action: :insert,
changes: %{
queries: [
%Query{
foo: nil,
bar: "5642"
},
%Query{
foo: nil,
bar: "5672"
}
]
},
errors: [],
data: #EmbeddedSchema.ClientInstance<>,
valid?: true
>
},
errors: [],
data: #Controller.ClientInstance<>,
valid?: true
>
I have this rendering via polymorphic_embed_inputs_for/4 the form successfully against the existing data
<%= polymorphic_embed_inputs_for query_form, :queries, :queryquery, fn fp -> %>, with the array of existing foo/bar fields present. On validation however, I only recieve a single one in the params passed back to the form as so:
%{
"notes" => "Misbehaving Tester.",
"query" => %{
"includes" => [""],
"queries" => %{
"__type__" => "queryquery",
"foo" => " ",
"bar" => "5672"
}
}
}
as opposed to an array like I was expecting
%{
"notes" => "Misbehaving Tester.",
"query" => %{
"includes" => [""],
"queries" => [
%{
"__type__" => "queryquery",
"foo" => " ",
"bar" => "5642"
},
%{
"__type__" => "queryquery",
"foo" => " ",
"bar" => "5672"
}]
}
}
I've been toying around with various solutions but I've reached a bit of an impasse at this time.
In my experience, you need to set the name of an input manually when working with array inputs. You can use the index and something like name="#{@name}[#{index}]".
I think what would be interesting is to see the rendering phoenix template and generated html). It's probably the names of the inputs that are wrong.
The to_form implementation of phoenix_ecto checks the cardinality of a field and sets the name and id to id: name <> "[" <> index_string <> "]" and id <> "_" <> index_string respectively.
https://github.com/phoenixframework/phoenix_ecto/blob/4aa366cfc26b06433521a92deff27b52cec6d450/lib/phoenix_ecto/html.ex#L69
I think the to_form implementation of polymorphic_embed needs to check whether the field is of type {:array, PolymorphicEmbed} and modify the name and id attributes accordingly.
https://github.com/mathieuprog/polymorphic_embed/blob/05f682cd2328907a207085240e45c7e3f42afacf/lib/polymorphic_embed/html/form.ex#L117