I've got schema with has_many association with :on_replace option set to :delete. And I've got the form with a group of checkboxes to submit new values to be put as associations to the parent entity. I want all previously set associations to be removed on edit, but instead I get new associations inserted into the database and old still persist in the database.
The changeset after submit has only new associations without id's in it's changes, like this:
%{materials: [#Ecto.Changeset<action: :insert,
changes: %{material: "Cast iron"}, errors: [],
data: #HrPro.Entities.Material<>, valid?: true>,
#Ecto.Changeset<action: :insert,
changes: %{material: "Steel"}, errors: [],
data: #HrPro.Entities.Material<>, valid?: true>]}
As you can see there are no :id fields in the changeset, so I expected that previously saved materials will be deleted from database but this is not the case.
The schema looks like this:
schema "entities" do
has_many :materials, Material, on_replace: :delete
end
def changeset(%Entity{} = entity, attrs \\ %{}) do
entity
|> cast(attrs, @allowed_fields)
|> cast_assoc(:materials)
end
My installation is:
phoenix 1.3
ecto 2.2.6
Can we make Ecto to clean all previously submitted associated values from the database on edit?
It appears that if the property on_replace: is set to :delete for some association in schema, when the changeset is created for such struct, Ecto automatically adds changes with action :replace for each of previously saved associations.
In my case the problem was that I used the new action: :ignore feature of the ecto to not allow Ecto pollute my database with empty values (if the corresponding checkbox is unchecked in the form). And this feature simply removes all the changes for empty associations from the changeset including those with action: :replace which are needed for Ecto to remove them from the database.
When I stopped ignoring empty values everything worked correctly.