RubyOnRails provides us with many model callbacks around the object’s lifecycle when object is being created, updated or destroyed. For example: before_create, after_create, before_update, after_destroy etc. We use them to write & run our code around the object’s lifecycle by defining a method and associating them as one of the callbacks.
But then how can we make a piece of code execute as a callback for any another defined method except create, update, save and destroy? For example, let’s say we have a model Article and we want to execute something just before and after an article is being published without hooking into model’s before_save and after_save callbacks?
RubyOnRails or more precisely ActiveRecord provides us with a module ActiveModel::Callbacks, which allows us to define and register custom callbacks using
define_model_callbacks method. Lets have a look at the snippet below for the above scenario:
class Article extend ActiveModel::Callbacks define_model_callbacks :publish, :only => [:before, :after] before_publish :check_publishability after_publish :notify_subscribers def publish run_callbacks :publish do puts "Publishing article..." end end private def check_publishability puts "Checking publishability rules..." end def notify_subscribers puts "Notifying subscribers..." end end
define_model_callbacks provides with all three callbacks i.e. before, after and around, but here in our example we have chosen to have just before and after callbacks by specifying a hash
:only => [:after, :before] since only those two were needed. By using
define_model_callbacks :publish, :only => [:after, :before] we got two new callback
after_publish, which we then used to register our callback methods.
So now when we will call
publish method on an article object,
check_publishability will be executed as a before callback and
notify_subscribers will be executed as an after callback for the
One point to note here is that the code in the
publish method should be wrapped in
run_callback :publish block, so that when it is called on an object, its callbacks are executed too.
For the snippet above
run_callback triggers before callbacks, yield the block given and then trigger after callbacks.
More information on define_model_callbacks can be found here.
>> article = Article.last >> article.publish Checking publishability rules... Publishing article... Notifying subscribers...