Ruby on Rails
HowToUseUndocumentedCallbacks (Version #11)

There are two semi-undocumented callbacks available to developers: after_find and after_initialize. Before we go any further explaining how these could be used and how to implement them, let me first echo the documentation:

Because after_find and after_initialize is called for each 
object instantiated found by a finder, such as Base.find_all, 
we’ve had to implement a simple performance constraint 
(50% more speed on a simple test case).

So, as you can see, using either of these callbacks can result in a huge performance hit, so continue at your own risk.

When

Say you are creating a system for managing insurance policies. Each policy has many different user types that may or may not be the same user depending on how differing companies run or policies are created. An example of this would be, a user Sally could be the introducing agent and the agent on a policy, but on a different policy she may only be the agent. You don’t want to have multiple Sally users in the system, so you sub-class your User class and create Agent, IntroducingAgent?, Adjuster, and Insured objects to represent the different types of users. You then create a has_and_belongs_to_many relationship between your Policy and User class and add a “type” column to your policies_users table. This will cause ActiveRecord to instantiate the different users when doing a find. You can now access these different types of users by iterating through the users array and checking the class type of that user. For example:

def agent
  for user in policy.users
    return user if user.is_a?(Agent)
  end
end

This allows you to access the agent user using policy.agent, but it has the side effect of iterating through the users array everytime a call is made to the agent method. Wouldn’t it be nice if the Policy class could populate agent, referring_agent, insured, etc. instance variables immediately when the Policy object is being created? Implementing an after_find callback can make this happen.

How

Continuing from the example above we are going to create instance variables to the Policy class and then define an after_find callback to populate them so that they can be accessed later. The after_find callback needs to be explicitly defined inside the protected section of a model class. For example:

class Policy < ActiveRecord::Base
  has_and_belongs_to_many :users

  attr :adjuster, true
  attr :agent, true
  attr :introducing_agent, true
  attr :insured, true

  protected
    def after_find
      for user in users
        case user
          when Adjuster then @adjuster = user
          when Agent then @agent = user
          when IntroducingAgent @introducing_agent = user
          when Insured then @insured = user
        end
      end
    end
end

Warning

This example may not be the best, but hopefully you get the idea. In most cases, I think it’s still better (and faster) to build custom find methods that add on this type of additional functionality. But this document was more created to suppliment the documentation of these “hidden” callback methods.

category:Howto

There are two semi-undocumented callbacks available to developers: after_find and after_initialize. Before we go any further explaining how these could be used and how to implement them, let me first echo the documentation:

Because after_find and after_initialize is called for each 
object instantiated found by a finder, such as Base.find_all, 
we’ve had to implement a simple performance constraint 
(50% more speed on a simple test case).

So, as you can see, using either of these callbacks can result in a huge performance hit, so continue at your own risk.

When

Say you are creating a system for managing insurance policies. Each policy has many different user types that may or may not be the same user depending on how differing companies run or policies are created. An example of this would be, a user Sally could be the introducing agent and the agent on a policy, but on a different policy she may only be the agent. You don’t want to have multiple Sally users in the system, so you sub-class your User class and create Agent, IntroducingAgent?, Adjuster, and Insured objects to represent the different types of users. You then create a has_and_belongs_to_many relationship between your Policy and User class and add a “type” column to your policies_users table. This will cause ActiveRecord to instantiate the different users when doing a find. You can now access these different types of users by iterating through the users array and checking the class type of that user. For example:

def agent
  for user in policy.users
    return user if user.is_a?(Agent)
  end
end

This allows you to access the agent user using policy.agent, but it has the side effect of iterating through the users array everytime a call is made to the agent method. Wouldn’t it be nice if the Policy class could populate agent, referring_agent, insured, etc. instance variables immediately when the Policy object is being created? Implementing an after_find callback can make this happen.

How

Continuing from the example above we are going to create instance variables to the Policy class and then define an after_find callback to populate them so that they can be accessed later. The after_find callback needs to be explicitly defined inside the protected section of a model class. For example:

class Policy < ActiveRecord::Base
  has_and_belongs_to_many :users

  attr :adjuster, true
  attr :agent, true
  attr :introducing_agent, true
  attr :insured, true

  protected
    def after_find
      for user in users
        case user
          when Adjuster then @adjuster = user
          when Agent then @agent = user
          when IntroducingAgent @introducing_agent = user
          when Insured then @insured = user
        end
      end
    end
end

Warning

This example may not be the best, but hopefully you get the idea. In most cases, I think it’s still better (and faster) to build custom find methods that add on this type of additional functionality. But this document was more created to suppliment the documentation of these “hidden” callback methods.

category:Howto