Sorry I couldn’t come up with a better title for this one!
I’m trying to use an Ecto Changeset to maintain a set of changes provided by a user, eventually, when the user clicks “Save”, the changes will be written to the database but for now I’m trying to use the changes to keep track of all requested changes so I can conditionally show/hide form elements and display validation messages. Each time the user makes a change to a field, I don’t necessarily receive all the params for all the other fields again. So whenever I get a change from the user, I add that change to a changeset that is already tracking all previous changes. I’m getting some unexpected behaviour though. It occurs in the case that the user edits a field of an embedded association, changing it back to its original value.
defmodule Page do
use Ecto.Schema
import Ecto.Changeset
schema "pages" do
embeds_one :background, Background, on_replace: :update do
field :color, :string
end
timestamps()
end
def background_changeset(schema, params) do
schema
|> cast(params, [:color])
end
@doc false
def changeset(schema, attrs) do
schema
|> cast(attrs, [])
|> cast_embed(:background, with: &background_changeset/2)
end
end
test "replacing a change in a changeset" do
page = %Page{background: %Page.Background{color: "red"}}
changed_to_blue = Page.changeset(page, %{"background" => %{"color" => "blue"}})
assert changed_to_blue.changes.background.changes == %{color: "blue"}
changed_to_green = Page.changeset(changed_to_blue, %{"background" => %{"color" => "green"}})
assert changed_to_green.changes.background.changes == %{color: "green"}
changed_back_to_red = Page.changeset(changed_to_green, %{"background" => %{"color" => "red"}})
assert changed_back_to_red.changes.background.changes == %{color: "red"}
# Assertion with == failed
# code: assert changed_back_to_red.changes.background.changes == %{color: "red"}
# left: %{color: "green"}
# right: %{color: "red"}
end
end
As you can see above, we can keep applying new changes to a changeset and they overwrite the previous changes, this is what I want. However, if we try to change the value back to the value contained in the Changeset’s data, the change is ignored.
Does this seem like unexpected behaviour? If so, I can post this as a Github issue for Ecto. Or am I misunderstanding/misusing changesets here?
Thanks!