web-dev-qa-db-ja.com

Elixir Ecto:チェンジセットでbelongs_toアソシエーションを設定する方法

チェンジセットとの関連付けを実際に設定する方法に少し行き詰まっています。モデルに次のコードがあります。

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})
14
Ole Spaarmann

@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})
14
Ole Spaarmann