We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Passing match suffix to ecto's foreign_key_constraint/3
jrowah
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.
@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.
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.
copied to clipboard