Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir 处理phoenix中现有表之间的多对多关系_Elixir_Phoenix Framework_Ecto - Fatal编程技术网

Elixir 处理phoenix中现有表之间的多对多关系

Elixir 处理phoenix中现有表之间的多对多关系,elixir,phoenix-framework,ecto,Elixir,Phoenix Framework,Ecto,我有一个用elixir/phoenix制作的web应用程序。 我将围绕标题进行解释。 所以我在系统中有一个叫做角色的东西,还有一个叫做权限 角色通过中间表角色权限与权限有多对多关系 三者的模式大致如下: 角色 schema "roles" do # associations has_many(:users, User) many_to_many(:permissions, Permission, join_through: "role_permissions")

我有一个用elixir/phoenix制作的web应用程序。 我将围绕标题进行解释。 所以我在系统中有一个叫做
角色
的东西,还有一个叫做
权限

角色
通过中间表
角色权限
权限有
多对多
关系

三者的模式大致如下:

角色

schema "roles" do
    # associations
    has_many(:users, User)
    many_to_many(:permissions, Permission, join_through: "role_permissions")

    field(:name, :string)
    field(:description, :string)

    timestamps()
  end 

@required_params ~w(name)a
@optional_params ~w(description)a
@create_params @required_params ++ @optional_params
@update_params @required_params ++ @optional_params

@doc """
Returns a changeset to create a new `role`.
"""
@spec create_changeset(t, map) :: Ecto.Changeset.t()
def create_changeset(%__MODULE__{} = role, params) do
 role
 |> cast(params, @create_params)
 |> common_changeset()
end
schema "permissions" do
    field(:code, :string)
    field(:description, :string)

    timestamps()
  end
 schema "permissions" do
    belongs_to(:role, Role)
    belongs_to(:permission, Permission)

    timestamps()
  end
权限

schema "roles" do
    # associations
    has_many(:users, User)
    many_to_many(:permissions, Permission, join_through: "role_permissions")

    field(:name, :string)
    field(:description, :string)

    timestamps()
  end 

@required_params ~w(name)a
@optional_params ~w(description)a
@create_params @required_params ++ @optional_params
@update_params @required_params ++ @optional_params

@doc """
Returns a changeset to create a new `role`.
"""
@spec create_changeset(t, map) :: Ecto.Changeset.t()
def create_changeset(%__MODULE__{} = role, params) do
 role
 |> cast(params, @create_params)
 |> common_changeset()
end
schema "permissions" do
    field(:code, :string)
    field(:description, :string)

    timestamps()
  end
 schema "permissions" do
    belongs_to(:role, Role)
    belongs_to(:permission, Permission)

    timestamps()
  end
角色权限

schema "roles" do
    # associations
    has_many(:users, User)
    many_to_many(:permissions, Permission, join_through: "role_permissions")

    field(:name, :string)
    field(:description, :string)

    timestamps()
  end 

@required_params ~w(name)a
@optional_params ~w(description)a
@create_params @required_params ++ @optional_params
@update_params @required_params ++ @optional_params

@doc """
Returns a changeset to create a new `role`.
"""
@spec create_changeset(t, map) :: Ecto.Changeset.t()
def create_changeset(%__MODULE__{} = role, params) do
 role
 |> cast(params, @create_params)
 |> common_changeset()
end
schema "permissions" do
    field(:code, :string)
    field(:description, :string)

    timestamps()
  end
 schema "permissions" do
    belongs_to(:role, Role)
    belongs_to(:permission, Permission)

    timestamps()
  end
权限可以与角色分开创建,因此我有CRUD函数来创建它们

但是,在创建
角色时,它们应该与
权限关联。
为了做到这一点,我使用了如下所示的create函数

def create(%{permissions: permissions} = params) when permissions != [] do
    Multi.new()
    |> Multi.run(:role, fn _ ->
      QH.create(Role, params, Repo)
    end)
    |> permissions_multi(params)
    |> persist()
  end

defp permissions_multi(multi, params) do
    Multi.run(multi, :permission, fn %{role: role} ->
      role_permissions = associate_role_permissions(role, params[:permissions])
      {count, _} = Repo.insert_all(RolePermission, role_permissions)
      {:ok, count}
    end)
  end

  defp associate_role_permissions(role, permissions) do
    Enum.map(permissions, fn permission ->
      [permission_id: permission,
      role_id: role.id,
      inserted_at: DateTime.utc_now,
      updated_at: DateTime.utc_now]
    end)
  end

  # Run the accumulated multi struct
  defp persist(multi) do
    case Repo.transaction(multi) do
      {:ok, %{role: role}} ->
        {:ok, role}

      {:error, _, _, _} = error ->
        error
    end
  end
create/1
包含
name
description
permissions
,这是权限ID的列表

角色首先插入到数据库中。插入后,我收到
{:ok,role}
我使用<代码> AsAsTyAyRoLyValue<代码>将ReLyid与所有权限ID配对,并使用<代码> RePo。p> 所有这些都很好,我已经为此编写了测试,它也很有效

当我移动到phoenix的UI时,问题出现了

控制器

def new(conn, _params) do
  changeset = RoleSchema.create_changeset(%RoleSchema{}, %{permissions: nil})
  render(conn, "new.html", changeset: changeset)
end
“new.html”如下:

<%= form_for @changeset, @action, [as: :role], fn f -> %>
  <%= input f, :name %>
  <%= input f, :description %>
  <%= multiple_select(f, :permissions, formatted_list(:permissions))%>
  <%= submit "Submit", class: "btn btn-primary submit-btn" %>
  <%= link("Cancel", to: role_path(@conn, :index), class: "btn btn-primary") %>
<% end %>
%>
我在这里试图做的是从 我正在加载的权限列表的格式为[{:code,:id}],可以正常工作

但我不断地收到错误

protocol Phoenix.HTML.Safe not implemented for #Ecto.Association.NotLoaded<association :permissions is not loaded>.
未为#exto.Association.NotLoaded实现协议Phoenix.HTML.Safe。
我知道错误是因为在变更集中数据字段 未加载权限

这个问题的解决方法应该是什么

是否有办法修改
变更集.data
字段中的特定字段,这是正确的方法吗?

您必须明确每个关联,
exto
不会默默地进行。您的
RoleSchema
:permissions
中有一个关联,由于它没有预加载到新创建的变更集中,因此它返回结构,该结构将临时替换实际值,直到加载关联为止

由于您正在此处创建一个
变更集
,只需显式更新其数据,如:

changeset = RoleSchema.create_changeset(%RoleSchema{})
changeset = update_in(changeset.data, &Repo.preload(&1, :permissions))
...