Ecto wants to delete records with wrong side

So I have a many_to_many relation, it works ok for populating the records, but not for deleting.
I created table with:

create table(:users_permissions, primary_key: false) do
  add :user_uuid, :uuid, [references(:users, [column: :uuid, type: :uuid, on_delete: :delete_all])]
  add :permission_uuid, :uuid, [references(:permissions, [column: :uuid, type: :uuid, on_delete: :delete_all])]
end

but the relationship in DB is not created on migration.

And permissions schema is:

schema "permissions" do
  field :uuid, :binary_id
  field :code, :string
  field :description, :string
  many_to_many(:users,
    User,
    [join_through: UserPermission,
      join_keys: [user_uuid: :uuid, permission_uuid: :uuid],
      on_replace: :delete,
      on_delete: :delete_all
    ])
end

Ecto goes with when I try to delete permission entry:

DELETE FROM "users_permissions" AS u0 WHERE (u0."user_uuid" = $1::uuid)

but it should go with

DELETE FROM "users_permissions" AS u0 WHERE (u0."permission_uuid" = $1::uuid)

:wave:

What if you switch the keys in join_keys?

Like

# ...
join_keys: [permission_uuid: :uuid, user_uuid: :uuid],
# ...

Why it should matter?

Check out Ecto.Schema — Ecto v3.11.1

  • :join_keys - Specifies how the schemas are associated. It expects a keyword list with two entries, the first being how the join table should reach the current schema and the second how the join table should reach the associated schema. In the example above, it defaults to: [post_id: :id, tag_id: :id] . The keys are inflected from the schema names.

In your case the current schema is for permissions, so I think permission_uuid should come first.

Thanks, let me check.

It works! Thank you very much.