Ecto - check_constraint - field param for table constraints?

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?

1 Like

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?


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.

1 Like

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)

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.