Why is collection = objects on has_many: through trigger callbacks in a union model when an association is deleted?

The Rails 4 documentation talks about destroying callbacks in the connection model for the has_many :through relationship:

collection=objects Replaces the contents of collections with deletion and adding objects as needed. If the: through option is true, callbacks in union models are triggered, except for the destruction of callbacks, since deletion is direct.

Fortunately, this is documented, but I want to know why this is actually so? Hopefully there is a technical reason, because otherwise it's just crazy!

In my case, I had a has_and_belongs_to_many relationship in the join table model to another model. Entries in this second join table will never be deleted if related entries in the first join table were deleted. I resorted to what feels hacked, and I have to repeat myself on each side of the relationship :through :

 has_many :schools_templates, dependent: :destroy has_many :templates, through: :schools_templates, before_remove: :remove_groups_school_templates private def remove_groups_school_templates(template) schools_templates.where(template: template).first.groups.clear end 

There is validation there to β€œensure” the uniqueness of the connection table entries between the two foreign keys, so I can call first in the callback.

+5
source share
2 answers

So I came across the same question the other day. In my case, I was doing something similar to what you were doing, and was facing the same problem when the connection table was deleted and not destroyed.

I started looking at the code, and I think the documentation is just out of date. has_many_through_association

All you have to do is add the dependent :: destroy to has_many: through the relationship.

 class User has_many :partnerships, dependent: :destroy has_many :partners, through: :partnerships, dependent: :destroy end 

The pain I was dealing with was:

 user.partner_ids = [1,2,3] #creates the relationships user.partner_ids = [] #was deleting the records from partnerships without callbacks. 

Dependent :: destroy the relationships of partners that are fixed. Callbacks are now running and everything is fine again.

0
source

Usually, if you want to delete something through the has_many association, you put dependent: :destroy there:

 class User has_many :partnerships, dependent: :destroy has_many :partners, through: :partnerships end 

If you want to destroy partners , as well as partnerships, you must add this dependency to the Partnership model:

 class Partnership belongs_to :partner, dependent: :destroy belongs_to :user end 

When an object is destroyed, it causes destruction on each object in which the destroy function is provided. Thus, User causes destruction on each Partnership , and each call of Partnership destroys on each Partner .

"Why can't it be used with through " - well, the answer is "from the moment you delete it directly." I know this doesn't say much (for me either), but, on the other hand, for me adding dependencies to objects that are not directly related is a bad idea. Consider the above example: if the dependent - destroy will work on partners and destroy them - should it also destroy the connection model? Of course, yes, because in another case it will lead to data corruption, but you may lose some data that may be associated with the connection model, so in some cases, no, you do not want to destroy the join model. This means that the Rails team would have to add a new parameter, delete_join , to indicate whether you want to save this model or not. And this is just a bad design, since we already have a better approach - add dependencies to the connection model.

+2
source

Source: https://habr.com/ru/post/1236765/


All Articles