Ecto has_many :through in form

2019-04-28 20:26发布

问题:

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!

回答1:

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.



回答2:

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