It seems that access to the ActiveRecord callback chain has changed recently, however the documentation still contains the following :
To list the methods and procs registered with a particular callback, append _callback_chain to the callback name that you wish to list and send that to your class from the Rails console.
This used to work in Rails 2.3.x and I’d used it a few times before, however trying to use it in Rails 3 gave me problems :
HourEntry.before_save_callback_chain
NoMethodError: undefined method `before_save_callback_chain' for #
After some digging around ActiveRecord then ActiveModel and ActiveSupport I figured I could just access the _#{type}_callbacks method and then reject and select these arrays to get what was required. This is what I came up with to get the before_save callbacks that I was interested in.
HourEntry._save_callbacks.select { |callback| callback.kind.eql?(:before) }
This returns me the array of callback objects that are chained before I call save on the HourEntry model. If I want to check for a particular proc being in that chain then I can do :
HourEntry._save_callbacks.select { |callback| callback.kind.eql?(:after) }.collect(&:filter).include?(:archive_if_no_users)
It’s not optimal chaining a number of enumerable methods but I think it seems pretty readable.
I am hoping that the callback_chain methods return at some point (though I only used them sparingly) but more than that I’m hoping someone might be able to set me straight on how I’m going about getting around the callback chains on ActiveRecord and ActiveModel.
Xavier Noria
Mar 28, 2011
Hi Aaron. Thanks for the post.
Please if you see any lie or inaccuracy in the documentation feel free to push a fix yourself via docrails, it has public write access :).
Aaron
Mar 29, 2011
Thanks Xavier. After your prompting I’m looking into that now :)
Xavier Noria
Mar 29, 2011
Saw the commits, thanks! :)
Prashant
Mar 31, 2011
Very usefull articles, these articles always push me to do some genius things
One question i want to ask apart from this post
How can skip callback on a particular object (save/update), there can be workaround.
But like in Rails 2.3.x, we do @user.send(:update_without_callbacks)
Is there any like this in Rails
Aaron
Mar 31, 2011
Prashant after having a look at AR 2.3 and AR 3.0 it looks like you were actually tapping some internal code.
Essentially actions with callbacks were alias_method_chained with :callbacks so part of a save would be to do callbacks then call *_without_callbacks (update_without_callbacks in your case).
The callback chain in AR3 eventually comes from ActiveSupport::Callbacks.CallbackChain which inherits from Array. I would say then that you *should* be able to call .clear on your _update_callbacks OR for each callback you want to remove using the above filtering just call .delete on the CallbackChain object.
Checkout the ActiveSupport::Callbacks module to dig a bit deeper.
Cheers
John
Aug 1, 2012
Thanks so much for posting this, it saved the day. Here’s what I used to get a list of the names of all the callbacks:
self.class._create_callbacks.select { |callback| callback.kind.eql?(:after) }.collect(&:filter)