has_many关联,一列存储多个关联

has_many association, store multiple associations in one column

我有两个 table,usersroles。我想做的是在它们之间创建简单的关联,即 users 可以有多个 roles.

在数据库中应该是这样的:

角色:

 id | name
-----------
  1 | ADMIN
  2 | USER

用户

id | email         | username | roles
-------------------------------------
 1  test@gmail.com    test      [1,2]

到目前为止,我得到了以下代码:

def change do
    create table(:users) do
      add :email, :string
      add :username, :string
      add :roles, references(:roles)
    end
  end

schema "users" do
    field :email, :string
    field :username, :string
    has_many :roles, TimesheetServer.Role

    timestamps()
  end

  def changeset(struct, params \ %{}) do
     struct
      |> cast(params, [:email, :username])
      |> validate_required([:email, :username])
  end

def change do
    create table(:roles) do
      add :name, :string
      timestamps()
    end
  end

schema "roles" do
    field :name, :string
    belongs_to :users, TimesheetServer.User
    timestamps()
  end

然后我尝试像这样播种数据库:

User.changeset(
    %User{},%{email: "test@gmail.com", username: "test", roles: [
        %Role{name: "ADMIN"},
        %Role{name: "USER"}
    ]})

    |> Repo.insert

不幸的是,这不会在 user table 中创建角色列表,也不会在 roles table.

中保存角色

任何帮助或提示将不胜感激!

如评论中所述,上述关系必须定义为many_to_many。要做到这一点,实际上有两种方法。

第一个是将角色模式定义为embedded_schema,在这种情况下它将嵌入到父(用户)中。这意味着不会为角色模式创建数据库 table。

第二种选择是通过协会加入他们table。可以如下所示:

迁移:

def change do
 create table(:users) do
   add :email, :string
   add :username, :string
 end

 create table(:roles) do
   add :name, :string, null: false
 end

 create table(:users_roles, primary_key: false) do
  add :user_id, references(:users, on_delete: :delete_all)
  add :role_id, references(:roles, on_delete: :delete_all)
 end

 create unique_index(:users_roles, [:user_id, :role_id])
end

用户模式:

 schema "users" do
  field :email, :string
  field :username, :string
  many_to_many :roles, TimesheetServer.Role, join_through: "users_roles"
 end

  def changeset(struct, params \ %{}) do
   struct
    |> cast(params, [:email, :username])
    |> validate_required([:email, :username])
  end
end

角色模式:

   schema "roles" do
     field :name, :string
     many_to_many :users, TimesheetServer.User, join_through: "users_roles"
   end

   def changeset(struct, params \ %{}) do
     struct
     |> cast(params, [:name])
     |> validate_required([:name])
   end

现在可以通过以下方式建立协会:

    user = Repo.get!(User, user_id) |> Repo.preload(:roles)
    role = Repo.get!(Role, role_id)

    user_changeset = Changeset.change(user)
                         |> Changeset.put_assoc(:roles, [role | user.roles])

这将导致三个 tables:

用户:

id | email         | username |
-------------------------------
 1  test@gmail.com    test     

角色:

 id | name
-----------
  1 | ADMIN
  2 | USER

users_roles:

user_id | role_id
------------------
      1 | 1
------------------
      1 | 2