I am trying to get a has_many :through
relationship working in Ecto for a many-many relationship between a User
model and Group
model.
The only information I was able to find online was related to nested attributes in a post by José Valim here (which is excellent, by the way).
Since the groups already exist in the system, I was hoping to do a multiple select input. I ran into a couple issues in doing that. I don't believe that it is possible to assign the groups
association in the changeset directly because I was getting an error every time I attempted to do so. My next thought was to do the work manually (finding, deleting, and inserting GroupMembership
records), however I wasn't sure if this was the right path to go down, and wanted to get some advice first.
Since the code sample has quite a few lines I made a gist here.
If it's preferred that I post it in this question directly, I can certainly do that.
Thanks for all the help!
Unfortunately Ecto 1.0 does not support many to many. It means you will need to receive the IDs and manually build the intermediate association for each group you are associating to the user. We hope to make this easier in future releases.
EDIT: Ecto 2.0 supports many_to_many.
The many_to_many
association introduced in Ecto 2.0 supports this use case through the join_through
option:
:join_through
- specifies the source of the associated data. It may be a string, like “posts_tags”, representing the underlying storage table or an atom, like MyApp.PostTag
, representing a schema. This option is required.
This means you can specify an Ecto schema for the join table and then point to it in the other two schemas, like in the following example:
defmodule MyApp.GroupMembership do
use Ecto.Schema
import Ecto.Changeset
schema "group_memberships" do
...
end
end
defmodule MyApp.Group do
use Ecto.Schema
import Ecto.Changeset
schema "groups" do
...
many_to_many :users, MyApp.User, join_through: MyApp.GroupMembership
end
end
defmodule MyApp.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
schema "users" do
...
many_to_many :groups, MyApp.Group, join_through: MyApp.GroupMembership
end
end