many_to_manyassociation happens through a join schema or source, containing foreign keys to the associated schemas. For example, the association below:
# from MyApp.Post
many_to_many :tags, MyApp.Tag, join_through: "posts_tags"
#is backed by relational databases through a join table as follows:
[Post] <-> [posts_tags] <-> [Tag]
id <-- post_id
tag_id --> id
Step by Step Guide
Create Tables
create table("todo_lists") do
add :title
timestamps()
end
create table("todo_items") do
add :description
timestamps()
end
create table("todo_list_x_items", primary_key: false) do
add :todo_item_id, references(:todo_items)
add :todo_list_id, references(:todo_lists)
#timestamps()
end
defmodule MyApp.TodoList do
use Ecto.Schema
schema "todo_lists" do
field :title
many_to_many :todo_items, MyApp.TodoItem,
join_through: MyApp.TodoListItem
# timestamps()
end
end
defmodule MyApp.TodoListXItem do
use Ecto.Schema
@primary_key false
schema "todo_list_items" do
belongs_to :todo_list, MyApp.TodoList
belongs_to :todo_item, MyApp.TodoItem
timestamps()
end
end
defmodule MyApp.TodoItem do
use Ecto.Schema
schema "todo_items" do
field :description
timestamps()
end
end
# In MyApp.TodoList
def changeset(struct, params \\ %{}) do
struct
|> Ecto.Changeset.cast(params, [:title])
|> Ecto.Changeset.cast_assoc(:todo_items, required: true)
end
# And then in MyApp.TodoItem
def changeset(struct, params \\ %{}) do
struct
|> Ecto.Changeset.cast(params, [:description])
end