Ecto has_many :through in form
Asked Answered
A

2

6

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!

Armenta answered 14/10, 2015 at 14:22 Comment(1)
I can't speak to the Ecto code but I can speak to DB design principles. Relational DB sorts will tell you that you can't model n to n relationships. What you do is build a relation table (in your case something like UsersInGroups) and then you build a 1-n from Users and Groups to that. I'm not sure it would help your Ecto issue but it's likely a better way to model your data. FWIW.Cinematograph
C
4

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.

Cupid answered 14/10, 2015 at 21:45 Comment(5)
Thanks for the heads up!Armenta
To confirm, Ecto does support has_many :through (via a join table), just not the Rails-style has_and_belongs_to_many. Is that right? Docs: hexdocs.pm/ecto/Ecto.Association.HasThrough.htmlSaddletree
@José is this still the case with the most recent version of ecto? (As of 2018 January, it's 2.27)Egg
Ecto has many_to_many (which is equivalent to has_and_belongs_to_many) since Ecto 2.0. :)Terminal
What Ecto provides, is not actually a good solution to the question of associating already existing records. cast_assoc and put_assoc are going to mess around with groups data as well, they basically require you to send entire changeset to them instead of simple ids. While the only requirements was to link both records together: write two ids in one table.Kalynkam
U
1

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
Unpaid answered 31/7, 2018 at 5:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.