HMT collection_singular_ids = removing merge moments directly, destroy callback does not work

Just ran into a problem with has_many: through combining and after / before-destroy callbacks that don't start.

Say I have users, groups, and intermediate relationships called members. I have a form that allows users to register in groups, creating a new membership record when they check the related checkboxes. Basically an array of group_ids.

It looks something like this:

Which group would you like to join? (check all that apply) [] Group A [] Group B [] Group C 

And I want to record activities such as joining a group or leaving a group in the activity log table, as well as other important less important tricks.

I have the following defined:

 class Group < AR::Base has_many :memberships has_many :users, :through => :memberships end class Membership < AR::Base belongs_to :user belongs_to :group after_create :log_event_to_audit_table after_destroy :log_event_to_audit_table end class User < ActiveRecord::Base has_many :memberships has_many :groups, :through => :memberships attr_accessible :group_ids # enables mass-assignment end 

When a new membership record is created, the after_create function runs as expected. However, after_destroy does not start!

After google-ing and reading the docs, I found the reason:

"Automatically deleting direct union models, do not destroy callbacks starts" - from Ruby Guides.

Hmmmmmm ...

Thus, the join model (in this case, membership) destroys callbacks that do not start. Good thing is coming down. Any reason why?

So my question is, what is the best way to get around this problem? Should I define my own member_ids = method in the user model that calls the membership.destroy function directly?

Discover all the best practice suggestions in this scenario.

Thanks!

+9
ruby-on-rails activerecord has-many-through
source share
3 answers

After a thorough study of the API documentation, it turns out that has_many and has_and_belongs_to_many ("HABTM") have several options for this case only:

  • before_add
  • after_add
  • before_remove
  • after_remove

 class User < ActiveRecord::Base has_many :groups, :through => :memberships, :after_remove => :your_custom_method end 

Judging by how many answers I got, this should not be a well-documented / used function.

I just note this here for myself and others who may stumble like me.

+11
source share

I recently ran into the same problem and solved it by expanding the association and overriding the delete method:

 class User < ActiveRecord::Base has_many :memberships has_many :groups, :through => :memberships do def delete(*args) groups = args.flatten # destroy memberships in order to trigger their callbacks: proxy_association.owner.memberships.where(group_id: groups).destroy_all super end end ... end 
0
source share

adding dependent: :destroy to the many relation actually calls the before_destroy and after_destroy in the Membership class.

 class User < ActiveRecord::Base has_many :groups, through: :memberships, dependent: :destroy end 
0
source share

All Articles