tsrandrei
tsrandrei

Reputation: 89

Delete/Destroy record on join_table with has_many through

I render a set of checkboxes and I want to delete all the Privilege of a User.

I have searched all the questions related, but unluckily none works.

Rails 5.2.3

User

has_many :user_privileges, class_name: 'UserPrivileges'
has_many :privileges, through: :user_privileges

Privilege

has_many :user_privileges, class_name: 'UserPrivileges'
has_many :users, through: :user_privileges

UserPrivileges

belongs_to :user
belongs_to :privilege

The issue kick in when I want to delete ( uncheck ) the last privilege-record of that user in the join_table.

The record is still there, and there is no way to delete/destroy that specific record.

My intuition recall to the callbacks, I have tried different ways of using dependent but the last record is still there.

Any tips are welcome.

Thanks

Upvotes: 1

Views: 1935

Answers (1)

demir
demir

Reputation: 4709

If you want to delete the record from the join table, you need to add dependent: :destroy to has_many :through relationship.

# privilege.rb
has_many :user_privileges, class_name: 'UserPrivileges'
has_many :users, through: :user_privileges, dependent: :destroy

See What gets deleted? in API docs:

There is a potential pitfall here: has_and_belongs_to_many and has_many :through associations have records in join tables, as well as the associated records. So when we call one of these deletion methods, what exactly should be deleted?

The answer is that it is assumed that deletion on an association is about removing the link between the owner and the associated object(s), rather than necessarily the associated objects themselves. So with has_and_belongs_to_many and has_many :through, the join records will be deleted, but the associated records won't.

To run dependent: :destroy callback, you must use the destroy or destroy_all method when deleting the privilege record.

See Delete or destroy? in API docs:

For has_many, destroy and destroy_all will always call the destroy method of the record(s) being removed so that callbacks are run. However delete and delete_all will either do the deletion according to the strategy specified by the :dependent option, or if no :dependent option is given, then it will follow the default strategy. The default strategy is to do nothing (leave the foreign keys with the parent ids set), except for has_many :through, where the default strategy is delete_all (delete the join records, without running their callbacks).

Upvotes: 1

Related Questions