ecto - 在多对多关系的中间 table 中设置字段

ecto - set field in intermediate table in many to many relationship

我有两个具有多对多关系的实体 Users 和 Rooms。

我在中间 table

添加了一个附加字段 permission

迁移:

 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

模式:

 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

我编写了一个将用户与房间相关联的变更集,它有效

  def changeset_update_user(room, user) do
    room
    |> cast(%{}, [:name])
    |> validate_required([:name])
    |> put_assoc(:users, [user])
  end

现在的问题是:每当我将用户关联到房间时,我也想设置权限字段。 像

  def changeset_update_user(room, user) do
    room
    |> cast(%{}, [:name])
    |> validate_required([:name])
    |> put_assoc(:users, [%{user_id: user.id, permission: "HOST"}])
  end

编辑:将用户与房间相关联的函数

  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

但随后我得到一个错误,提示 user_id 和权限是未知字段

您得到的是 unknown field :permission,因为这不是 User 字段,而是 RoomUser 字段。

如文档中所述,当您不需要关心中间 table 时,many_to_many/3 是一种便利:因为您需要 permission,所以情况并非如此. 引用文档:

If you need to access the join table, then you likely want to use has_many/3 with the :through option instead.

想法描述here

在你的例子中翻译成:

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

然后您可以将 put_assoc 替换为:

|> put_assoc(:room_users, [%{user: user, permission: "HOST"}])