I have this many to many relation between users and facilities:
schema "facilities" do
field(:name, :string)
field(:description, :string)
many_to_many(:users, User, join_through: "users_facilities")
end
schema "users" do
field(:first_name, :string)
field(:last_name, :string)
field(:email_address, :string)
field(:username, :string)
many_to_many(:facilities, Facility, join_through: "users_facilities")
end
This is the changeset_params
:
%{
name: john,
users: [%{id: 1286, name: "john doe"}, %{id: 1287, name: "jane doe"}]
}
It works fine for the has_many
and give me a single changeset for the entire associations. but didn't work for many to many
.
The records_struct
have complete facilities association loaded with users
This is the code:
Facility.changeset(records_struct, changeset_params)
|> Ecto.Changeset.cast_assoc(:users)
I get changeset returned from Facility.changeset but Ecto.Changeset.cast_assoc
throws internal server
error when I try to test it.
Your users and facilities are managed independently. In other words, you don't create a new facility within the user's changeset and vice-versa. You want just to bind/associate to already existing entities, right?
For this case, you need Ecto.Changeset.put_assoc/4
Remember that you will need the association to be preloaded before doing put_assoc
.
Also be sure to set on_replace option in your many_to_many
associations, like:
many_to_many(:users, User, join_through: "users_facilities", on_replace: :delete)
For the many to many associations you most likely want a :delete
.
It means that when you pass associated records in the changeset it will remove associations with the records that were associated before but they are not in the current changeset. It will not delete associated records.