如何使用cast_assoc生成多个嵌套的变更集

时间:2017-07-24 18:13:29

标签: nested elixir phoenix-framework

我的会员资格,名单,项目和记忆定义如下:

schema "lists" do
  has_many :itemlists, Learnit.Itemlist, on_delete: :delete_all
  many_to_many :items, Learnit.Item, join_through: Learnit.Itemlist
  has_many :memberships, Learnit.Membership, on_delete: :delete_all
end

schema "memberships" do
  belongs_to :list, Learnit.List
  has_many :memorys, Learnit.Memory, on_delete: :delete_all
end

schema "itemlists" do
  belongs_to :item, Learnit.Item
  belongs_to :list, Learnit.List
end

schema "items" do
  has_many :itemlists, Learnit.Itemlist
  many_to_many :lists, Learnit.List, join_through: Learnit.Itemlist
  has_many :memorys, Learnit.Memory
end

schema "memorys" do
  belongs_to :membership, Learnit.Membership
  belongs_to :item, Learnit.Item
end

我的会员资格模型

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

我的记忆模型

def changeset(struct, params \\ %{}) do
  struct
  |> cast(params, [:status, :membership_id, :item_id])
  |> foreign_key_constraint([:membership_id, :item_id])
  |> unique_constraint(:membership_id_item_id)
  |> validate_required([:membership_id, :item_id])
end

我尝试创建新的成员资格并生成与一个查询相关的记忆。我需要通过其列表获得与成员资格相关联的第一个项目。然后我的计划是使用Membership的cast_assoc属性将整个保存在Repo中。

如何在会员资格的变更集中加载这些项目? 项目已经正确加载,我得到一个Map.put / 4 Undefined ...

def create(conn, %{"membership" => membership_params}) do
  memories = %{}
  list =
    List
    |> Repo.get!(membership_params["list_id"])
    |> Repo.preload(:items)
    |> Map.get(:items) # Get the list of items
    |> Enum.map(&load_items(&1, memories)) # Loop through the list to get each item
  IO.inspect(memories)
  Map.put(membership_params, :memorys, memories)
  membership_with_memories = Membership.changeset(%Membership{}, membership_params)
  case Repo.insert(membership_with_memories) do
    {:ok, _} ->
      conn
      |> put_flash(:info, "Membership created successfully.")
      |> redirect(to: list_path(conn, :index))
    {:error, membership_with_memories} ->
      Logger.debug("Membership : failed to save membership")
      conn
      |> put_flash(:alert, "Membership was not created.")
      |> redirect(to: topic_path(conn, :index))
  end
end

defp load_items(item, memories) do
  item
  |> Map.put(memories, :item, item) # Add item to the hash
end

2 个答案:

答案 0 :(得分:0)

我找到了正确加载params的方法,但我仍然无法找到将其保存在repo中的方法(我得到一个“无法将给定列表转换为字符串”)。

  

%{“list_id”=> “1”,     “memorys”=> [%{“item_id”=> “1”},%{“item_id”=> “2”},%{“item_id”=> “3”}],     “user_id”=> “1”}

def create(conn, %{"membership" => params}) do
  memories = []
  params =
    List
    |> Repo.get!(params["list_id"])
    |> Repo.preload(:items)
    |> Map.get(:items) # Get the list of items
    |> Enum.map(&add_items(&1, memories)) # Loop through the list to get list of item ids
    |> (&Map.put(params, "memorys", &1)).() # Add the list to membership params
    |> IO.inspect()
  membership_with_memories = Membership.changeset(%Membership{}, params)
  case Repo.insert(membership_with_memories) do
    {:ok, _} ->
      conn
      |> put_flash(:info, "Membership created successfully.")
      |> redirect(to: list_path(conn, :index))
    {:error, membership_with_memories} ->
      Logger.debug("Membership : failed to save membership")
      conn
      |> put_flash(:error, "Membership was not created.")
      |> redirect(to: list_path(conn, :index))
  end
end

defp add_items(item, memories) do
  memories ++ %{"item_id" => Kernel.inspect(item.id)} # Make sure id is a string
end

答案 1 :(得分:0)

刚刚在我的记忆模型中发现了问题。我真的不明白为什么validate_required会阻止cast_assoc,但对我来说这很好......

 def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:status, :membership_id, :item_id])
    #|> foreign_key_constraint([:membership_id, :item_id])  # Dont use that !
    |> unique_constraint(:membership_id_item_id) # Dont forget to put constraint on table too
    |> validate_required([:item_id]) # Cannot use :membership_id with cast_assoc
  end