Hello :D !
I'm trying to find the best way to update the join table of a many_to_many relation with just an array of the relation IDs.
I don't want to preload all the relations, because I'm just changing the join table.
This seems quite simple, my schema has :
many_to_many :groups, Group, join_through: "products_groups"
The client-side sends through the form an array of IDs of groups : { group_ids: ["1", "2"] }.
In Ruby's ActiveRecord and Mongoid, has_and_belongs_to_many relations automatically create a *_ids setter and getter on the object. So you can directly pass your hash containing the key *_ids and the magic of the ORM will automatically update the join table.
In Ecto, there's no such way, so I've come up with adding a virtual attribute and a function returning a Multi like this:
...
field :group_ids, {:array, :integer}, virtual: true
...
def group_ids_join(%Ecto.Multi{} = multi, %Ecto.Changeset{changes: %{group_ids: group_ids}} = changeset) do
multi
|> Multi.delete_all(:remove_group_ids, (from pg in "products_groups", where: pg.product_id == ^
changeset.data.id))
|> Multi.insert_all(:insert_group_ids, "products_groups", Enum.map(group_ids, fn group_id -> %{product_id:
changeset.data.id, group_id: group_id} end))
end
def group_ids_join(%Ecto.Multi{} = multi, _), do: multi
Do you see a better way of handling this use case?
Like said, it's working fine, but I hope that this feature would somehow be integrated directly in Ecto as it looks like a very common use case.