Rails 3: alias_method_chain still used? Rails 3: alias_method_chain still used? ruby ruby

Rails 3: alias_method_chain still used?


No, it has been replaced by a clever use of method overriding in modules and the super keyword.

Basically, you define the original function in an included module, and override it in another included module. When you call super in the overriding function, it calls the original function. But there is one catch. You have to include the extending modules after including the base module, and in the order you want the chaining to occur.

class Something  module Base      def my_method      # (A) original functionality    end  end  module PreExtension    def my_method      # (B) before the original      super # calls whatever was my_method before this definition was made    end  end  module PostExtension    def my_method      super # calls whatever was my_method before this definition was made      # (C) after the original    end  end  include Base # this is needed to place the base methods in the inheritance stack  include PreExtension # this will override the original my_method  include PostExtension # this will override my_method defined in PreExtensionends = Something.news.my_method #=> this is a twice extended method call that will execute code in this order:#=> (B) before the original#=> (A) the original#=> (C) after the original

Ryan Bates of Railscasts talks about how this is used in the Rails Routing code. I'd recommend watching it, and his other screencasts. They have the power to transform a knitting grandmother into a Rails guru.

PS: Credit goes to Peeja for correcting a fundamental error in my original answer. Thanks.


In general, a module can never override a method in the classit's included in. This is because module inclusion works justlike subclassing. A superclass can't override its subclasses'methods either, nor would you expect it to.

When a module is included in a class, the module is insertedjust after the class in the class's ancestor chain. Callingsuper from the class will call the module's implementation.

class Something  module PreExtension; end  module PostExtension; end  include PreExtension  include PostExtensionendSomething.ancestors # => [Something, Something::PostExtension, Something::PreExtension, Object, Kernel]

Whenever a method is called on a Something, Ruby looks throughthis list in order and calls the first implementation it finds.If the implementation calls super, it keeps looking and findsthe next one.

This means that modules included later take precedence overmodules included earlier, and can call super to get the earliermodules' implementations. This is because included modules areinserted in the ancestor chain directly after the class. Thisis how the routing code edgerunner mentioned works. That codeputs everything in modules, like so:

class SomethingNew  module Base    def my_method      puts "(A)"    end  end  module Extension    def my_method      puts "(B)"      super    end  end  include Base  include ExtensionendSomethingNew.new.my_method# Output:# >> (B)# >> (A)SomethingNew.ancestors # => [SomethingNew, SomethingNew::Extension, SomethingNew::Base, Object, Kernel]

This is why alias_method_chain existed in the first place. If putting the base code in a module is not an option, I'm not sure how to accomplish the equivalent of alias_method_chain.


I see that alias_method_chain is no longer present in Rails 3.0.0. http://api.rubyonrails.org/ doesn't report it and rails console reports it to be undefined local variable or method.

See Also - https://rails.lighthouseapp.com/projects/8994/tickets/285-alias_method_chain-limits-extensibility#ticket-285-20

UPDATE: As noted by @ecoologic in comments, alias_method_chain is still present in Rails 3.1.1.