How to use Ecto has_many and cast_assoc

I am new to Elixir and Ecto, and I will need help with Ecto has_many and cast_assoc. I can’t understand the basics, for example, how can I create a new model with an associate.

Here is my Has_Model:

defmodule Example.Has_Model do
  use Ecto.Schema
  import Ecto.Changeset
  alias Example.Repo
  alias Example.Has_Model

  schema "has_models" do
    has_many :belong_models, Example.Belong_Model
    field :name, string
    timestamps
  end

  def changeset(has_model, params \\ %{}) do
    has_model
    |> cast(params, [:name])
  end
end

and here is Belong_Model:

defmodule Example.Belong_Model do
  use Ecto.Schema
  import Ecto.Changeset
  alias Example.Repo
  alias Example.Belong_Model

  schema "belong_models" do
    belongs_to :has_model, Example.Has_Model
    field :name, string
    timestamps
  end

  def changeset(belong_model, params \\ %{}) do
    belong_model
    |> cast(params, [:name])
    |> cast_assoc(:has_model, required: true)
  end
end

Now, what I'm trying to do is create Has_Model first

iex()> changeset = Example.Has_Model.changeset(%Has_Model, %{name: "I have"})
iex()> Example.Repo.insert(changeset)

This work is done fine.

Then I would like to create a new Belong_Model and use the previously created Has_Model with it:

iex()> has = Example.Has_Model |> Example.Repo.get_by(name: "I have")
iex()> changeset = Example.Belong_Model.changeset(%Belong_Model, %{name: "I belong", belongs_to: has})

And here he fails:

** (Ecto.CastError) expected params to be a map, got: `%Example.Has_Model{__meta__: #Ecto.Schema.Metadata<:loaded, "has_models">, id: 1, inserted_at: #Ecto.DateTime<2016-10-04 19:39:38>, name: "I have", updated_at: #Ecto.DateTime<2016-10-04 19:39:38>, belong_models: #Ecto.Association.NotLoaded<association :belong_models is not loaded>}`
    (ecto) lib/ecto/changeset.ex:345: Ecto.Changeset.do_cast/4
    (example) lib/example/models/has_model.ex:15: Example.Has_Model.changeset/2
    (ecto) lib/ecto/changeset/relation.ex:99: Ecto.Changeset.Relation.do_cast/5
    (ecto) lib/ecto/changeset/relation.ex:235: Ecto.Changeset.Relation.single_change/5
    (ecto) lib/ecto/changeset.ex:571: Ecto.Changeset.cast_relation/4
    (example) lib/example/models/belong_model.ex:16: Example.Belong_Model.changeset/2

What is happening and what is the solution? I tried to enable these options all day long, but I just don't get it.

+4
source share
1 answer

I think you are looking for build_assoc / 3

iex()> has = Example.Has_Model |> Example.Repo.get_by(name: "I have")
iex()> belong_assoc = Ecto.build_assoc(has, :belong_models, has_model_id: has.id, name: "I belong")
iex()> Repo.insert!(belong_assoc)

cast_assoc/3 :

iex()> changeset = Example.Belong_Model.changeset(%Belong_Model, %{name: "I belong", has_model: %{name: "I have"})
iex()> Repo.insert!(changeset)

:

changeet.params, changeet

+1

Source: https://habr.com/ru/post/1656735/


All Articles