Custom model callbacks in RubyOnRails

By Akhil Bansal July 7, 2014

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

By default 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 before_publish and 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 publish method.

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...

Share this:

Leave a comment

Your email address will not be published. Required fields are marked *