silverdr
Ecto strange (?) one-to-many validation errors on children
I have a one-to-many relation where I – say – add items to cart. Once I add one item it’s fine. When I add another I get:
errors: [id: {"has already been taken", []}]
on the second item, even if it’s not persisted. The whole changeset looks (simplified) like:
#Ecto.Changeset<
action: :validate,
changes: %{
[...]
items: [
#Ecto.Changeset<
action: :insert,
changes: %{
description: "gin",
[...]
},
errors: [],
data: #MyApp.Cart.Item<>,
valid?: true
>,
#Ecto.Changeset<
action: :insert,
changes: %{
description: "tonic",
[...]
},
errors: [id: {"has already been taken", []}],
data: #MyApp.Cart.Item<>,
valid?: false
>
],
},
errors: [],
[...]
valid?: false
>
I “put” the action “validate” on the parent in the changeset like:
changeset = %Cart{}
|> Cart.changeset(add_static_fields(params, socket))
|> Map.put(:action, :validate)
but apparently children have action “insert” in their respective changesets. Since I am not “inserting” the parent anyway, why do the children complain about their “id being taken”? No id’s been assigned yet, or what part of my brain is not working today?
First Post!
al2o3cr
Can you show the code for Item.changeset? I’ve got several questions:
- where are the
Itemchangesets getting any value forid? - who is adding that error?
- the DB-side uniqueness validations would need to somehow get ahold of an
Ecto.Repo; is there anything unusual inCart.changeset?
Last Post!
dodo
Hi, thank you for the quick reply!
I am using regular auto-incrementing integer ids (bigserial). I set the id of newly created items to -1 in the frontend to avoid nullable types, I just ended up not sending those in the request to fix the issue.
The action field is not set manually, I am using cast_assoc with a has_many relation and on_replace: :delete because the frontend always sends all associations. The error appeared when the action was :update on the root entity and :insert on the associated (has_many) entities, those were preloaded but empty before updating.
I understand that Ecto relies on the id for finding existing entities and proceed depending on the on_replace option, but I thought the id would just be ignored when it does not match any existing entity.
Now that I think about it I actually prefer the existing behavior, it seems safer than just ignoring invalid ids
.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #elixirconf-us
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









