Rails 3: alias_method_chain still used?

后端 未结 3 580
醉酒成梦
醉酒成梦 2020-11-27 12:21

I was just reading about Gems/Plugin development for Rails 3 and ran across this post that says that alias_method_chain is no longer used. I can see the method is still ther

3条回答
  •  抹茶落季
    2020-11-27 13:05

    In general, a module can never override a method in the class it's included in. This is because module inclusion works just like 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 inserted just after the class in the class's ancestor chain. Calling super from the class will call the module's implementation.

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

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

    This means that modules included later take precedence over modules included earlier, and can call super to get the earlier modules' implementations. This is because included modules are inserted in the ancestor chain directly after the class. This is how the routing code edgerunner mentioned works. That code puts 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 Extension
    end
    
    SomethingNew.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.

提交回复
热议问题