Search code examples
elixirecto

How can I set up foreign_key_constraint on model deletion with Ecto?


I have 2 models, User and Role. User has_many Roles. I set up foreign key constraint also (you can't delete role if there is any user who has this role).

I get error when I'm trying to implement

Role
|> Repo.get(id)
|> Repo.delete

The error is:

 ** (Ecto.ConstraintError) constraint error when attempting to delete struct:

     * foreign_key: users_role_id_fkey

 If you would like to convert this constraint into an error, please
 call foreign_key_constraint/3 in your changeset and define the proper
 constraint name. The changeset defined the following constraints:

     * foreign_key: roles_users_fkey

I have no idea about how to add this foreign_key_constraint on deletion. I tried to write it by myself, like:

def delete_changeset(struct) do
  struct
  |> cast(%{}, [])
  |> foreign_key_constraint(:users)
end

and inserted it before |> Repo.delete. But it doesn't work. How can I add foreign_key_constraint here?

UPDATE

Migration files:

defmodule MyApp.Repo.Migrations.CreateRole do
  use Ecto.Migration

  def change do
    create table(:roles) do
      add :name, :string, null: false

      timestamps()
    end

    create unique_index(:roles, [:name])
  end
end

Add role_id to users:

defmodule MyApp.Repo.Migrations.AddRoleIdToUsers do
  use Ecto.Migration

  def up do
    alter table(:users) do
      add :role_id, references(:roles, on_delete: :nothing)
      remove :role
    end
  end
end

Solution

  • I solved it by

    |> foreign_key_constraint(:users, name: :users_role_id_fkey)
    

    in delete changeset. But it returns terrible error

    %{ "users" => ["doesn't exist"] }
    

    in the changeset. What the hell? I want to have correct error in the changeset