If I have a table constraint that involves multiple fields, what should I be entering in the field argument in Ecto changeset’s check_constraint function? Should one just arbitrary pick any column name or pass in the table name instead?
From what I know, a check constraint must be on a single field. Maybe you have another type of constraint that isn’t a check constraint. Could you show how your constraint is defined in your migration?
edit:
Sorry I was wrong that limitation doesn’t exist. From the source code it seems like you can pick any column you want and the error will be put there in the changeset.
Given errors in a changeset are stored per field you need to decide which field to add an error to if the constraint is triggered.
Hate to revive old threads, but I have some contextual information that might be helpful for anyone finding this (Google, Bing, etc.)
I had the same basic question as the original poster here. I have a check constraint which checks for state across multiple columns. I also know other constraint types, for example unique_constraint/3
, accept multiple columns for the field parameter whereas check_constraint/3
doesn’t. This made me curious as to what the different constraint functions were doing and why the discrepancy.
Looking into the source code of unique_constraint/3
I saw this bit:
def unique_constraint(changeset, [first_field | _] = fields, opts) do
constraint = opts[:name] || unique_index_name(changeset, fields)
message = message(opts, "has already been taken")
match_type = Keyword.get(opts, :match, :exact)
error_key = Keyword.get(opts, :error_key, first_field)
add_constraint(changeset, :unique, to_string(constraint), match_type, error_key, message)
end
The important part here is that the function above is resolving to a single field for the error reporting. This is in the documentation of unique_constraint/3
, but as someone with this post’s specific question the significance may not jump out at you:
:error_key
- the key to which changeset error will be added when check fails, defaults to the first field name of the given list of fields.
Ultimately the reason unique_constraint/3
accepts multiple fields is not because it’s going associate a violation error with those multiple fields (its not), but because it needs them to construct the default name of the unique constraint index. check_constraint/3
doesn’t need this (check constraints aren’t named like this) so it only takes the single field that it will use to attach the error to.