You can replicate the code in my original example in an IEX interactive shell.
I’ve done some more playing about with it in iex and here is the process I took:
defmodule Order do
use Ecto.Schema
schema "orders" do
embeds_many :items, Item, on_replace: :delete #added on_replace to allow manipulation
end
end
defmodule Item do
use Ecto.Schema
embedded_schema do
field :title
end
end
With zero items attached to the order:
order = %Order{}
changesetWithNoItems = Ecto.Changeset.change(order)
changesetWithNoItems.data
%Order{__meta__: #Ecto.Schema.Metadata<:built, "orders">, id: nil, items: []}
# this doesn't make sens
changesetWithNoItems |> Ecto.Changeset.put_change(:items, [])
#Ecto.Changeset<
action: nil,
changes: %{items: []},
errors: [],
data: #Order<>,
valid?: true
>
# Makes sense
changesetWithNoItems |> Ecto.Changeset.put_change(:items, nil)
#Ecto.Changeset<
action: nil,
changes: %{},
errors: [items: {"is invalid", [type: {:array, :map}]}],
data: #Order<>,
valid?: false
>
# Makes sense
changesetWithNoItems |> Ecto.Changeset.put_change(:items, [%Item{id: 1, title: "test"}])
#Ecto.Changeset<
action: nil,
changes: %{
items: [
#Ecto.Changeset<action: :insert, changes: %{}, errors: [], data: #Item<>,
valid?: true>
]
},
errors: [],
data: #Order<>,
valid?: true
>
Then with an order that has a single item attached:
order = %Order{items: [%Item{id: 1, title: "what"}]}
changesetWithItem = Ecto.Changeset.change(order)
changesetWithItem.data
%Order{
__meta__: #Ecto.Schema.Metadata<:built, "orders">,
id: nil,
items: [%Item{id: 1, title: "what"}]
}
# Makes sense
changesetWithItem |> Ecto.Changeset.put_change(:items, [%Item{id: 1, title: "what"}])
#Ecto.Changeset<action: nil, changes: %{}, errors: [], data: #Order<>,
valid?: true>
# Doesn't make sense
changesetWithItem |> Ecto.Changeset.put_change(:items, [%Item{id: 1, title: "huh"}])
#Ecto.Changeset<action: nil, changes: %{}, errors: [], data: #Order<>,
valid?: true>
# confirming
(changesetWithItem |> Ecto.Changeset.put_change(:items, [%Item{id: 1, title: "huh"}])).data
%Order{
__meta__: #Ecto.Schema.Metadata<:built, "orders">,
id: nil,
items: [%Item{id: 1, title: "what"}]
}
# Doesn't make sense
changesetWithItem |> Ecto.Changeset.put_change(:items, [%Item{id: 2, title: "huh"}])
#Ecto.Changeset<
action: nil,
changes: %{
items: [
#Ecto.Changeset<action: :replace, changes: %{}, errors: [], data: #Item<>,
valid?: true>,
#Ecto.Changeset<action: :insert, changes: %{}, errors: [], data: #Item<>,
valid?: true>
]
},
errors: [],
data: #Order<>,
valid?: true
>
# Confirming
((changesetWithItem |> Ecto.Changeset.put_change(:items, [%Item{id: 1, title: "huh"}, %Item{id: 2, title: "something new"}])).changes.items |> hd).data
%Item{id: 1, title: "huh"}