ActiveRecord::Observer, update_all and has_many

Hi,

I’m using an ActiveRecord::Observer to log users changing data in my
application. However, I’ve noted that adding an item to a has_many
relationship gets logged, but removing the item does not. That is:

@product.users << user

is logged, but:

@product.users.delete(user)

is not.

I’ve dug into ActiveRecord and found that the underlying issue is that
the HasManyAssociation delete_records method uses update_all to update
the record. update_all bypasses the normal call backs and therefore also
bypasses the Observer.

Is there a way to get an Observer to observe update_all calls?

I’ve worked out a solution. It might not be the neatest, but it works
for me:

has_many has its own call backs. So I can trigger a logging activity
using the ‘after_remove’ call back like this:

has_many :users, :after_remove => :log_removal

I am then able to grab the Observe object using ObjectSpace:

def get_an_active_activity_logger
active_loggers = Array.new
ObjectSpace.each_object(ActivityLogger){|l| active_loggers << l}
@activity_logger = active_loggers.first
end

And call one of @activity_logger’s public methods to generate the log.

def log_removal(item)
get_an_active_activity_logger
@activity_logger.log_activity(
self,
‘item_removal’,
“#{item.class.name} #{item.id} removed from association”
)
end

It means I have to update each of my has_many calls and make the
log_removal and get_an_active_activity_logger methods available to the
models where they are needed, but both of those are fairly trivial
tasks.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs