Cast_assoc changesets

In the documentation for cast_assoc changesets. I couldn’t find proper way of using it.

if I have two models:

  defmodule User do


 use Gallery.Web, :model


schema "users" do
field(:name, :string)
field(:occupation, :string)
has_many(:paintings, Painting)

end


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


 defmodule Painting do


 use Gallery.Web, :model


schema "paintings" do
field(:name, :string)

belongs_to(:users, User)

end


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

I have a user and then its associated paintings . I want to build single changeset fro these.

    data= %User{
          __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
         id: 4606,
         name: "Test",
         occupation: "Artist",
         paintings: [
     %Painting{
     __meta__: #Ecto.Schema.Metadata<:loaded, "paintings">,
    user_id: 4606,
    id: 1515,
    name: "philip"
   },
 %Painting{
__meta__: #Ecto.Schema.Metadata<:loaded, "paintings">,
 user_id: 4606,
 id: 1516,
 name: "john"
 }
]
}

Thanks.

:wave:

# in User
def changeset(struct, params \\ %{}) do
  struct
  |> cast(params, [:name, :occupation])
  |> cast_assoc(:paintings)
  |> validate_required([:name, :occupation])
end

Thanks for your reply. I need it for update. And i think i have to make it a map instead of struct.

You can put cast_assoc in the user changeset

  cast_assoc(:paintings)

Then preload the associated users with painitng and send the update map. It should work

   User
  |> Repo.get_by(id: user_id)
  |> Repo.preload(:paintings)
  |> User.changeset(data)
  |> Repo.update

Make sure to clean up your data to make it a simple map. Or it won’t work.

1 Like