The example presented here is an abstraction. Assume external text input, “country” in this case should be unique. But I get (Ecto.ConstraintError) when I insert duplicates.
The :on_conflict option does not work in this case, or I didn’t use the right syntax: Repo.insert(on_conflict: [ set: [updated_at: now()] ], conflict_target: :name)
I think cast_assoc is the only way to insert all associated data with a single query. For simplicity I only included a single relation; I know about the other functions but I think those would require to execute more queries, so I don’t know which is the best practice.
This is a bit late, but it might help someone with the same/similar issue.
I had a similar issue and solved it by adding the repo_opts property to the changeset on which I wanted to handle the unique constraint:
defmodule Country do
# ...schema definition...
def changeset(country, attrs) do
country
|> cast(attrs, [...])
|> validate_required([...])
# the repo_opts is an escape hatch that can be used on changesets
|> Map.put(:repo_opts, [on_conflict: :replace_all, conflict_target: :name])
end
end
# This will be inserted properly
%Account{}
|> Repo.preload(:country)
|> Account.changeset(%{name: "Duck", country: %{name: "USA"} })
|> Ecto.Changeset.cast_assoc(:country, with: &Country.changeset/2)
|> Repo.insert()