【问题标题】:Elixir Ecto: How to set a belongs_to association in a changesetElixir Ecto:如何在变更集中设置 belongs_to 关联
【发布时间】:2016-12-30 12:58:33
【问题描述】:

我有点纠结于如何实际设置与变更集的关联。我的模型中有这段代码:

defmodule MyApp.MemberApplication do
  use MyApp.Web, :model
  use Ecto.Schema
  use Arc.Ecto.Schema

  alias MyApp.Repo
  alias MyApp.MemberApplication

  schema "applications" do
    field :name, :string
    field :email, :string
    field :time_accepted, Ecto.DateTime
    field :time_declined, Ecto.DateTime
    belongs_to :accepted_by, MyApp.Admin
    belongs_to :declined_by, MyApp.Admin

    timestamps()
  end

  def set_accepted_changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:time_accepted, :accepted_by_id])
    |> cast_assoc(params, :accepted_by)
    |> set_time_accepted
  end

  defp set_time_accepted(changeset) do
    datetime = :calendar.universal_time() |> Ecto.DateTime.from_erl
    put_change(changeset, :time_accepted, datetime)
  end
end

我想保存与执行特定操作(接受或拒绝 member_application)的Admin 的关联和时间戳。时间戳的生成有效,但是当我尝试保存关联时,我总是收到错误

** (FunctionClauseError) no function clause matching in Ecto.Changeset.cast_assoc/3

这就是我想要设置关联的方式:

iex(26)> application = Repo.get(MemberApplication, 10)
iex(27)> admin = Repo.get(Admin, 16)
iex(28)> changeset = MemberApplication.set_accepted_changeset(application, %{accepted_by: admin})

【问题讨论】:

  • 试试Application.set_accepted_changeset(application, %{accepted_by_id: admin.id})|> cast_assoc(:accepted_by)
  • 这行得通。会写下答案

标签: elixir ecto


【解决方案1】:

感谢@Dogbert。这就是我让它工作的方式

defmodule MyApp.MemberApplication do
  use MyApp.Web, :model
  use Ecto.Schema
  use Arc.Ecto.Schema

  alias MyApp.Repo
  alias MyApp.MemberApplication

  schema "applications" do
    field :name, :string
    field :email, :string
    field :time_accepted, Ecto.DateTime
    field :time_declined, Ecto.DateTime
    belongs_to :accepted_by, MyApp.Admin
    belongs_to :declined_by, MyApp.Admin

    timestamps()
  end

  def set_accepted_changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:time_accepted, :accepted_by_id])
    # Change cast_assoc 
    |> cast_assoc(:accepted_by)
    |> set_time_accepted
  end

  defp set_time_accepted(changeset) do
    datetime = :calendar.universal_time() |> Ecto.DateTime.from_erl
    put_change(changeset, :time_accepted, datetime)
  end
end

然后直接预加载关联并设置ID。或者直接在查询中做:

iex(26)> application = Repo.get(MemberApplication, 10)
iex(27)> application = Repo.preload(application, :accepted_by)
iex(28)> admin = Repo.get(Admin, 16)
iex(29)> changeset = MemberApplication.set_accepted_changeset(application, %{accepted_by_id: admin.id})

【讨论】:

  • 您应该接受您自己的答案,以便将其显示为有解决方案。
  • 在这种情况下,你应该如何关联validate_requireness?是关联本身还是id?
  • 你真的不需要加载管理员,因为你只传递了 16 的 id,对吧?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多