Skip to content

Polymorphic embeds are not kept as changesets but are turned into structs - as opposed to what happens with ordinary embeds  #74

Description

@maxmarcon

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
>

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions