Are ActiveRecord callbacks called in the join tabl

2019-08-08 04:51发布

问题:

While testing acts_as_audited, I discovered (as also described here) that the :with_associations flag does not produce audit table entries for HABTM relationships.

For example:

User < ActiveRecord::Base
  has_and_belongs_to_many: :groups
  acts_as_audited, with_associations: groups

Group < ActiveRecord::Base
  has_and_belongs_to_many: :users
  acts_as_audited, with_associations: users

(and tested variations, ie. with/without with_associations)

In the source, one can see that all acts_as_audited does is adds callbacks like before_update and after_create to the audited tables. Apparently these are not added to the join tables.

I tried making a model like:

GroupsUsers < ActiveRecord::Base
  acts_as_audited

  after_save: :test

  def test
    logger.debug "test"
  end

but did not see any additions to the audit table for CRUD operations on Users or Groups. I can see the SQL statement acting on the join table in the logs so this suggests that the join table is altered internally in such a way that the normal callbacks are bypassed.

Is this true? Any suggestions for getting acts_as_audited to notice the join table or to log HABTM associations?

回答1:

Association callbacks has_and_belongs_to_many

Similar to the normal callbacks that hook into the life cycle of an Active Record object, you can also define callbacks that get triggered when you add an object to or remove an object from an association collection.

class Project
  has_and_belongs_to_many :developers, after_add: :evaluate_velocity

  def evaluate_velocity(developer)
    ...
  end
end

It's possible to stack callbacks by passing them as an array. Example:

class Project
  has_and_belongs_to_many :developers,
                          after_add: [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
end

Possible callbacks are: before_add, after_add, before_remove and after_remove.

If any of the before_add callbacks throw an exception, the object will not be added to the collection.

Similarly, if any of the before_remove callbacks throw an exception, the object will not be removed from the collection.