Friday, February 15, 2013

Experimenting Rails Callback Class

(This experiment is performed using Ruby version 1.9.3 and Rails version 3.0.9)

An ActiveRecord model object experiences different states during its life cycle. Typically, it starts with creation, experiences several modification, saved to database and finally gets destroyed. We can write callbacks (ruby methods) that will be triggered upon each state change of model objects.

Callbacks are just ruby methods. Then what's callback class? A Callback class is just a group of methods where you can put your callback handlers and thus they can be shared among different models.

Let's say we have an Dog class, which has an instance variable called favorite_food. The table dogs has an attribute called name. What we want is whenever an Dog object is initialized, values will be assigned to favorite_food and name.

class Dog
  attr_accessor :favorite_food
end

We need to create a callback class. Let's call it SharedCallbacks. And we need to define a method called after_initialize, which is the same name of the event we want it to handle.

class SharedCallbacks
  def after_initialize(model)
    model.favorite_food = 'meat'
    model.name = 'This is a dog'
  end
end

The parameter "model" is the object on which the callback method will have effect on, which in this case is any Dog object.

Back to Dog class, now what we need to do is to create a SharedCallbacks object and hook it with the after_initialize declaration.

class Dog
  attr_accessor :favorite_food
  after_initialize SharedCallbacks.new
end

So whenever a Dog object is initialized, an new SharedCallbacks object is created and the corresponding callback method, which is after_initialize in this case, is called using the Dog object as the single parameter. As a result, the Dog object's favorite_food and name are set to the desired values.

Now let's add another requirement, whenever a record is found in database, its name will be set to  'This is a cat'. What we need to do is define a after_find method in SharedCallbacks class and hook one of its object with the after_find callback declaration in Dog class.

class SharedCallbacks
  def after_initialize(model)
    model.favorite_food = 'meat'
    model.name = 'This is a dog'
  end

  def after_find(model)
    model.name = 'This is a cat'
  end
end

class Dog
  attr_accessor :favorite_food
  after_initialize SharedCallbacks.new
  after_find SharedCallbacks.new
end

If we retrieve a record from database and look into it, we're gonna find that its name is set to 'This is a dog', NOT 'This is a cat'. That's because the after_initialize callback is always invoked after after_find. In the book Agile Web Development with Rails, there is a complete order in which callbacks are invoked, if they are declared of course.

No comments:

Post a Comment