Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elixir Ecto: How to set a belongs_to association in a changeset

Tags:

elixir

ecto

I am a bit stuck in how to actually set an association with a changeset. I have this code in my model:

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

I want to save an association to the Admin that performed a certain operation (accepting or declining an member_application) and a timestamp. The generation of the timestamp works but when I try to save an association I always get the error

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

This is how I want to set the association:

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})
like image 464
Ole Spaarmann Avatar asked Aug 23 '16 15:08

Ole Spaarmann


People also ask

What is ecto changeset?

8.4) Changesets allow filtering, casting, validation and definition of constraints when manipulating structs. There is an example of working with changesets in the introductory documentation in the Ecto module. The functions cast/4 and change/2 are the usual entry points for creating changesets.

What is ecto in Elixir?

Ecto is the go-to database toolkit in the Elixir ecosystem, usually used to interact with SQL databases like Postgres and MySQL. It is very powerful and can be used for all the interaction with databases you need, such as inserting, validating, changing, and querying data. It has four main components: Schema.


1 Answers

Thanks @Dogbert. This is how I got it to work

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

And then preload the association and set the ID directly. Or do it directly in the query:

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})
like image 194
Ole Spaarmann Avatar answered Nov 21 '22 22:11

Ole Spaarmann