Reputation: 63
I have two entities Users and Rooms with a many to many relationship.
I've added an additional field permission
to the intermediate table
Migration:
def change do
create table(:room_users) do
add :permission, :string
add :user_id, references(:users)
add :room_id, references(:rooms)
end
create unique_index(:room_users, [:user_id, :room_id])
end
Schemas:
schema "rooms" do
field :name, :string
many_to_many :users, User, join_through: "room_users"
timestamps()
end
...
schema "users" do
field :username, :string
many_to_many :rooms, Room, join_through: "room_users"
timestamps()
end
I've written a changeset that associates a user with a room, which works
def changeset_update_user(room, user) do
room
|> cast(%{}, [:name])
|> validate_required([:name])
|> put_assoc(:users, [user])
end
Now the question: whenever I associate a user to a room I also want to set the permission field. Something like
def changeset_update_user(room, user) do
room
|> cast(%{}, [:name])
|> validate_required([:name])
|> put_assoc(:users, [%{user_id: user.id, permission: "HOST"}])
end
EDIT: function to associate user with room
def create_Room_with_User(attrs \\ %{}, user) do
{result, room_dto} = %Room{}
|> Room.changeset(attrs)
|> Repo.insert()
Repo.preload(room_dto, :users)
|> Room.changeset_update_user(user)
|> Repo.update()
{result, room_dto}
end
But then I get an error that user_id and permission are unknown fields
Upvotes: 1
Views: 746
Reputation: 3204
You are getting an unknown field :permission
because this is not a User
field, but a RoomUser
field.
As explained in the docs, many_to_many/3
is a convenience when you don't need to care about the intermediate table: since you need permission
, this is not the case.
Quoting the doc:
If you need to access the join table, then you likely want to use
has_many/3
with the :through option instead.
The idea is described here.
Translated in your example, this becomes:
defmdoule Room do
use Ecto.Schema
schema "rooms" do
field :name, :string
has_many :room_users, RoomUser
has_many :users, through: [:room_users, :user]
end
end
defmodule User do
use Ecto.Schema
schema "users" do
field :name, :string
has_many :room_users, RoomUser
has_many :rooms, through: [:room_users, :room]
end
end
defmodule RoomUser do
use Ecto.Schema
schema "room_users" do
field :permission, :string
belongs_to :user, User
belongs_to :room, Room
end
end
You can then replace your put_assoc
with:
|> put_assoc(:room_users, [%{user: user, permission: "HOST"}])
Upvotes: 3