Warning: I am a novice at Elixir, Phoenix, and Ecto. I'll update this post as I am corrected. Note also that this applies to Phoenix 1.2.0 and Ecto 2.0.2.
Updated: July 11. There is no need for a join table model. See also this post from OvermindDL1.
Phoenix and Ecto have recently (I gather) gotten explicit support for many-to-many associations (via join tables). I found that making them work was uncharacteristically hard, hence this blog post.
Note: my job was probably made harder because I didn't want to make the join table a first class model object with a primary key and changesets and all that. That is, I was working from this bit of documentation:
What I wanted
There are users and organizations. Organizations have many users and users can belong to many organizations.
You can find the source behind this post at Github.
This is the same as what the documentation says. The migration looks like this:
def change do create table(:users_organizations, primary_key: false) do add :user_id, references(:users, on_delete: :delete_all) add :organization_id, references(:organizations, on_delete: :delete_all) end
Save yourself grief: end the fields with
Each of the
Organization models describe the many-to-many relationship. (Note that the name of the column in the join table is inferred.)
defmodule Eecrit.User do use Eecrit.Web, :model schema "users" do #... many_to_many :organizations, Eecrit.Organization, join_through: "users_organizations" #...
defmodule Eecrit.Organization do use Eecrit.Web, :model schema "organizations" do #... many_to_many :users, Eecrit.User, join_through: "users_organizations" #...
You do not need an
What now works (not this blog engine's syntax highlighting, as it turns out)
See also seed.exs.