# Passing match suffix to ecto's foreign_key_constraint/3 

TIL that ecto's foreign_key_constraint/3 can match constraint names by suffix. You don't have to list every constraint by its full name. You write the shared end of the name once, and Ecto matches every constraint that ends with it.

Here is an example;

A shop must not delete a product that customers have already ordered, reviewed or saved. Each of those tables points at products with on_delete: :restrict, so the database rejects the delete. The changeset turns that rejection into {:error, changeset}, so the delete doesn't raise Ecto.ConstraintError.

Five tables refer to a product as product_id. Promotions refer to it as featured_product_id.

You might list every constraint by its exact name.
```elixir
@in_use_constraints [
  :order_items_product_id_fkey,
  :cart_items_product_id_fkey,
  :reviews_product_id_fkey,
  :wishlist_items_product_id_fkey,
  :stock_movements_product_id_fkey,
  :promotions_featured_product_id_fkey
]

def delete_changeset(product) do
  Enum.reduce(@in_use_constraints, change(product), fn name, changeset ->
    foreign_key_constraint(changeset, :id, name: name, message: "is in use")
  end)
end
```
After: the constraints are matched by suffix.
```elixir
def delete_changeset(product) do
  product
  |> change()
  |> foreign_key_constraint(:id, name: :product_id_fkey, match: :suffix, message: "is in use")
end
```
The tradeoff is that this depends on your database constraint naming convention. A custom name without that suffix needs a separate declaration. Good thing is auto-generated fkeys by ecto often follow a similar convention.

---

Created by: jrowah
Date: November 02, 2026
URL: https://elixirdrops.net/d/ULKDR4do
