#---Callback/Hook Methods---

The most common Callback methods in Ruby are:

  • Module’s included method
  • Module’s prepended method
  • Module’s extended method
  • Class’s inherited method

These are called when a module is included, prepended, or extended in a class,
Or when a class is inherited from another class.

Examples

Module callbacks:

module Trainable
  def self.included(base)
    p "Module Trainable included in #{base}"
  end
  def self.prepended(base)
    p "Module Trainable prepended in #{base}"
  end
  def self.extended(base)
    p "Module Trainable extended in #{base}"
  end
end
class Person
  include Trainable
end
class Robot
  prepend Trainable
end
class Machine
  extend Trainable
end
## Just executing the above code will print:
## => "Module Trainable included in Person"
## => "Module Trainable prepended in Robot"
## => "Module Trainable extended in Machine"

Class callback:

class Animal
  def self.inherited(subclass)
    p "Class Animal inherited by #{subclass}"
  end
end
class Dog < Animal
end
## Just executing the above code will print:
## => "Class Animal inherited by Dog"

It even works with multi-level inheritance:

class Labrador < Dog
end
## => "Class Animal inherited by Labrador"

Callback Uses

There are two I can think of:

1. Callback Use One:
Like how some good parents set up some advantage for their children even before they are born, ruby classes and modules can use these callback methods to set up some initial state or behavior for the classes and modules that include/prepend/extend/inherit from them later on.

(Weird analogy, I know. But I’m thinking of certain things now.)

Rails has this example where a parent class sets up the inheriting child class’s activerecord associations via the inherited callback for a test case:

=begin ## comment block because I didn't install Rails
class Device < ActiveRecord::Base
  def self.inherited(subclass)
    subclass.belongs_to :person, \
    inverse_of: subclass.name.demodulize.tableize.to_sym
    subclass.filter_attributes = [:secret_attribute, \
    :"#{subclass.name.demodulize.downcase}_key"]
  end
end
class Computer < Device; end
=end

Computer class gets the belongs to person association and the filter_attributes without doing any work.

2. Callback Use Two:
We know including a module in a class makes the module methods as the class’s instance methods.
And extending a module in a class makes the module methods as the class’s class methods.
But what if we have a module that has some methods that will be used as instance methods, and some others that’ll be used as class methods? This is a practical use case.
We can use this common pattern to do that:

module Trainable
  def self.included(base)
    base.extend(ClassMethods)
  end
  module ClassMethods
    def train
      "Training #{self}"
    end
  end
  def run
    "#{self} is running"
  end
end
class Person
  ## this gives both the class method `train` and the
  ## instance method `run`
  include Trainable
end
p Person.train
p Person.new.run

Notes

  • ActiveSupport::Concern - A popular module that enhances the above functionality with some elegant api. It’s typically used in Rails apps to DRY up model and controller classes.
  • Apparently, there are also some other callback methods like method_added, method_removed, method_undefined, etc. But I didn’t know them until I wrote this page. Find them in the Module documentation.