I’ve read some guides and the documentation, but I have not really grokked it yet.
I’m trying to set up a many to many relationship between Cameras and Summaries.
A Summary can have one or many Cameras.
I’ve created a table like this:
def change do
create table(:summaries_cameras, primary_key: false) do
add :summary_id, references(:summaries, on_delete: :delete_all)
add :camera_id, references(:cameras, on_delete: :delete_all)
end
create unique_index(:summaries_cameras, [:summary_id, :camera_id])
end
And I’ve changed both modules like this:
schema "summaries" do
field :name, :string
timestamps(type: :utc_datetime)
many_to_many :cameras, MyApp.Cameras.Camera, join_through: "summaries_cameras"
schema "cameras" do
field :name, :string
timestamps(type: :utc_datetime)
many_to_many :cameras, MyApp.Cameras.Camera, join_through: "summaries_cameras"
So far so good, but I’m struggling to understand how I associate 2 cameras with a summary.
Here I’ve started on a test:
test "associations" do
camera1 = camera_fixture()
camera2 = camera_fixture()
summary = summary_fixture()
# Make both cameras belong to the summary
# What to do here?
end
You can also go with the explicit approach, where you define a schema for the relations table and insert the relations explicitly in a transaction, highly depends on the use-case.
test "assosiations" do
import MyApp.WizardFixtures
import MyApp.CamerasFixtures
alias MyApp.Wizard.Summary
alias MyApp.Repo
camera1 = camera_fixture()
camera2 = camera_fixture()
summary = summary_fixture()
summary = Repo.preload(summary, [:cameras])
summary_changeset = Ecto.Changeset.change(summary)
summary_cameras_changeset = summary_changeset |> Ecto.Changeset.put_assoc(:cameras, [camera1, camera2])
Repo.update!(summary_cameras_changeset)
summary = Repo.reload(summary)
summary = Repo.preload(summary, :cameras)
assert summary.cameras == [camera1, camera2]
end
The code
defmodule MyApp.SummaryCamera do
use Ecto.Schema
schema "summaries_cameras" do
belongs_to :summary, MyApp.Wizard.Summary
belongs_to :camera, MyApp.Cameras.Camera
timestamps()
end
def changeset(struct, params \\ %{}) do
struct
|> Ecto.Changeset.cast_assoc( :camera, required: true)
|> Ecto.Changeset.cast_assoc( :summary, required: true)
end
end
The migration:
def change do
create table(:summaries_cameras, primary_key: false) do
add :summary_id, references(:summaries)
add :camera_id, references(:cameras)
end
create unique_index(:summaries_cameras,
[:summary_id, :camera_id])
end
defmodule MyApp.Wizard.Summary do
use Ecto.Schema
import Ecto.Changeset
schema "summaries" do
many_to_many :cameras, MyApp.Cameras.Camera,
join_through: "summaries_cameras"
defmodule MyApp.Wizard.Summary do
use Ecto.Schema
import Ecto.Changeset
schema "summaries" do
many_to_many :cameras, MyApp.Cameras.Camera,
join_through: "summaries_cameras"