2
votes

I'm pretty new to the Phoenix, Ecto ecosystem. I'm trying to create in between table for handling many to many relation. Unfortunately I have no idea how to create changeset (to insert it) holding both user and event data and I have big trouble finding that information in the available sources. Could you help? At least point i the right direction?

When I was doing another task with relations i was using build/2, but it only takes one assoc param.

I have created following structure:

Table 1, data with events:

schema "events" do
    field :name, :string
    field :address, :string

    field :location_x, :float
    field :location_y, :float

    field :date, Ecto.DateTime

    field :description, :string

    has_many :presences, Kpsz.Model.Presence
  end

Table 2, data with users:

schema "users" do
    field :login, :string
    field :password, :string
    field :email, :string

    field :role, :integer

    field :name, :string
    field :surname, :string
    field :class, :string
    field :phone_number, :string
    field :avatar, :string

    has_many :presences, Kpsz.Model.Presence

    timestamps
  end

And in-between table holding user presences for events:

schema "presences" do
    belongs_to :user, Kpsz.Model.User, foreign_key: :user_id
    belongs_to :event, Kpsz.Model.Event, foreign_key: :event_id
  end

def changeset(user, params \\ :empty) do
    user
      |> cast(params, @required_fields, @optional_fields)
      |> foreign_key_constraint(:user_id)
      |> foreign_key_constraint(:event_id)
  end
1

1 Answers

3
votes

The following schema definitions should accomplish what you are wanting to do (simplified from the schemas you provided):

defmodule Event do
  use Ecto.Model
  schema "events" do
    has_many :presences, Presence
    has_many :users, through: [:presences, :user]
  end
end

defmodule User do
  use Ecto.Model
  schema "users" do
    has_many :presences, Presence
    has_many :events, through: [:presences, :event]
  end
end

defmodule Presence do
  use Ecto.Model
  schema "presences" do
    belongs_to :user, User
    belongs_to :event, Event
  end
end

See the documentation for Ecto.Schema.has_many/3 with the :through option for more information.

Preloading the :through association will also preload the connected association, for example:

iex> event = Event |> Repo.get!(1) |> Repo.preload([:users])
iex> # at this point, both event.presences and event.users have been loaded

Inserting a Presence record can also just be done directly:

iex> presence = %Presence{ user_id: 1, event_id: 1 } |> Repo.insert!