No_assoc_constraint with has_many, through:

I have a database level constraint on not allowing a record to be deleted if it has associations.

I’d like to delete one of the parents of these records, with an appropriate error if any of its children have associations.

As an example, a project might have multiple groups, each of which have users.

has_many :users, through: [:groups, :users]

I’d like to be able to delete a project, and if the groups are not empty, then return an error.

If I try

project
|> Ecto.Changeset.change
|> Ecto.Changeset.no_assoc_constraint(:users)
|> Repo.delete

I get an error:

** (ArgumentError) no_assoc_constraint can only be added to has one/many associations, got: %Ecto.Association.HasThrough...

Is there a way to get no_assoc_constraint to work with through?

The reason no_assoc_constraint does not work with through is because they rely on database constraints and database constraints cannot go “through” tables. Instead you need to define two constraints, from A → B and then B → C, and check for those as appropriate.

1 Like