Say user input params (from a form, GraphQL document, etc.) look like below (let’s say a User has many Articles ):
%{
"name" => "John",
"articles" => [5, 9, 18]
}
or I can change it to below if that’s better:
%{
"name" => "John",
"articles" => [%{id: 5}, %{id: 9}, %{id: 18}]
}
The user has selected a list of articles through a multi-select component.
How should I insert/update the association articles
for the User?
1 Like
Adzz
August 8, 2020, 9:43am
2
There are a few ways.
Use Nested Changesets
Insert each item individually in a transaction. (You would need to insert the user first so you have it’s id, then each article).
Use an EctoMulti.
The mutli is the same idea as 2 just a different way to do it.
If the user exists already you can upsert the user instead.
For 1 you can either do something like this:
Ecto.Changeset.cast(%User{}, changes, [:name])
|> Ecto.Changeset.cast_assoc(:articles)
Read more about cast assoc here https://link.medium.com/ZVBaeIrqM8
And check out the docs here https://hexdocs.pm/ecto/Ecto.Changeset.html
1 Like
I want to use changeset; I don’t really see a reason to go for the 2. or 3. suggestion here.
Giving a list of IDs won’t work for cast_assoc
(e.g. [5, 9, 18]
). This is what is sent from Absinthe.
I’m not sure how to best solve this problem.
1 Like
Adzz
August 8, 2020, 10:42am
4
Each element needs to be the shape of an article, then it should just work. Are you getting an error message?
I guess the question then is how to get that shape:)
I receive a list of IDs from Absinthe. Those articles always exist, because the user selected those from a multi-select component. I can’t just pass that list of IDs to cast_assoc
. The changeset will be invalid if I do so for “articles” field.
I need to replace all the articles IDs a user has by the list of articles IDs received from the Absinthe query.
Eventually I loaded all those entities by the ID list with a query (where id in ^ids).
Then added those entities in the changeset via put_assoc
.