Thursday, May 20, 2010

Rails alias_method_chain explained with pictures!

I've been meaning to do this for a while because I keep coming across alias_method and alias_method_chain in Rails code. I understood what was going on, but felt that I never grokked it. So, I finally mapped out what happens, drew some pictures, and, voila! Enlightenment!

Since I firmly believe that the best way to learn something is to teach it, I thought I would document what I learned in the hopes that it will be beneficial to someone else and firmly cement my understanding. So without further ado:

It is important to keep in mind that a method name is essentially a constant symbol and points to a block of code. "alias_method" is a Ruby class Module method with the signature:

alias_method(new_name, old_name)

And, "alias_method_chain" looks like this:

alias_method_chain :method_name, :feature

That's the easy part.

For the purpose of this example, I'm examining the behavior of:

alias_method_chain :render, :feature

The alias_method method makes a copy of the method block and assigns the new_name constant to point to the copy of the method block. So, it looks something like this:

Here's the method render and its method block:

After we call alias_method :render_without_feature, :render we have the following:
At this point, if we wanted to, we could redefine the render method, which would replace the original {render} block with new functionality. And, as it is often explained, the original functionality is still available at the render_without_feature method.

However, as it is often explained, what is desired in Rails library code is to redefine an existing method while saving the original functionality under a new name. Therefore, what we see in Rails code was often:

alias_method :render_without_feature, :render
alias_method :render, :render_with_feature

We already looked at the first line. Let's look at the second line.

The second line is assigning the constant "render" to a copy of the "render_with_feature" functionality. It looks like this:
Now, render will call the code block with the new feature and render_without_feature will call the original render block.

This is the key to the entire Rails helper, alias_method_chain, which takes the name of the original method and the name of the feature and does this mapping for us.

Therefore, the two alias_method calls above can be replaced with the following:

alias_method_chain :render, :feature

You, the fine engineer, will define a method render_with_feature and the render symbol will point to it. And, after the alias_method_chain call, you will have a new render_without_feature method created for you.

I find all of this rather elegant and hope this has been helpful