polymorphic_embed
polymorphic_embed copied to clipboard
Polymorphic embeds are not kept as changesets but are turned into structs - as opposed to what happens with ordinary embeds
Observed behavior: When I build a changeset with ordinary embeds, these embeds stay changesets. When I build the changesets with polymorphic embeds, the embeds are turned into structs if they're valid.
Expected behavior: I would expect polymorphic embeds to be kept as changeset until I call apply_changes
or apply_action
on the parent changeset, just as normal embeds do.
Ecto version: 3.9.4 polymorphic_embed version: 3.0.5
Here's a working example:
Mix.install([{:ecto, "~> 3.9.4"}, {:polymorphic_embed, "~> 3.0.5"}])
defmodule ChildSchema do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field(:name, :string)
field(:age, :integer)
end
def changeset(source \\ %__MODULE__{}, changes) do
cast(source, changes, [:name, :age])
end
end
defmodule ParentSchema do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
embeds_many(:children, ChildSchema)
end
def changeset(source \\ %__MODULE__{}, changes) do
cast(source, changes, [])
|> cast_embed(:children)
end
end
defmodule ParentSchemaWithPolymorphicChildren do
use Ecto.Schema
import PolymorphicEmbed
import Ecto.Changeset
embedded_schema do
polymorphic_embeds_many(:children,
types: [
child_schema: ChildSchema
],
on_replace: :delete,
on_type_not_found: :raise
)
end
def changeset(source \\ %__MODULE__{}, changes) do
cast(source, changes, [])
|> cast_polymorphic_embed(:children)
end
end
ParentSchema.changeset(%{children: [%{name: "Tic", age: 10}, %{name: "Tac", age: 12}]})
|> IO.inspect(label: "changeset for schema with traditional embeds: embeds are still changesets")
ParentSchemaWithPolymorphicChildren.changeset(%{
children: [
%{name: "Tic", age: 10, __type__: "child_schema"},
%{name: "Tac", age: 12, __type__: "child_schema"}
]
})
|> IO.inspect(
label: "changeset for schema with polymorphic embeds: embeds are have already been applied"
)
Result of executing the above code:
changeset for schema with traditional embeds: embeds are still changesets
#Ecto.Changeset<
action: nil,
changes: %{
children: [
#Ecto.Changeset<
action: :insert,
changes: %{age: 10, name: "Tic"},
errors: [],
data: #ChildSchema<>,
valid?: true
>,
#Ecto.Changeset<
action: :insert,
changes: %{age: 12, name: "Tac"},
errors: [],
data: #ChildSchema<>,
valid?: true
>
]
},
errors: [],
data: #ParentSchema<>,
valid?: true
>
changeset for schema with polymorphic embeds: changes in embeds have already been applied
#Ecto.Changeset<
action: nil,
changes: %{
children: [
%ChildSchema{
id: "cd555105-4033-425f-b984-29f8c2062de9",
name: "Tic",
age: 10
},
%ChildSchema{
id: "5c55473d-e1d5-4f76-96a9-b63685c55ca3",
name: "Tac",
age: 12
}
]
},
errors: [],
data: #ParentSchemaWithPolymorphicChildren<>,
valid?: true
>