Rails 3:仍然使用alias_method_chain?

我刚刚阅读了关于Rails 3的Gems / Plugin开发,并跑过这篇文章 ,说alias_method_chain不再使用。 我可以看到activesupport-3.0.0 / lib / active_support / core_ext / module / aliasing.rb中的方法仍然存在。

我还应该在Rails 3中使用alias_method_chain吗?

这是否仍然反映了Rails 3中想要修改ActiveRecord的gems / plugins的最佳实践?

不,它已经被模块和super关键字的巧妙使用方法覆盖所取代。

基本上,您可以在包含的模块中定义原始函数,并在另一个包含的模块中覆盖它。 当你在覆盖函数中调用super时,它会调用原始函数。 但是有一个问题。 包含基本模块之后,您必须包含扩展模块,并且按照您希望链接发生的顺序。

 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 PreExtension end s = Something.new s.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 

Railscasts的 Ryan Bates谈到了如何在Rails路由代码中使用它 。 我build议观看它和他的其他屏幕录像。 他们有能力把一个编织祖母变成一个Rails大师。

PS:信用去Peeja纠正我原来的答案的基本错误。 谢谢。

通常情况下,模块不能重写它包含的类中的方法。这是因为模块包含像子类一样工作。 超类不能覆盖它的子类的方法,也不期望它。

当一个模块被包含在一个类中时,该模块被插入类的祖先链中的类之后。 调用super 将调用模块的实现。

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

每当某个方法被调用时,Ruby就会依次查找这个列表并调用它find的第一个实现。 如果实现调用super ,它会继续查找并find下一个。

这意味着稍后包含的模块优先于之前包含的模块,并且可以调用super来获得早期模块的实现。 这是因为包含的模块直接在课后插入祖先链中。 这就是路由代码edgerunner提到的工作方式。 该代码将所有内容放在模块中,如下所示:

 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] 

这就是为什么alias_method_chain首先存在的原因。 如果把基本代码放在一个模块中不是一个选项,我不知道如何完成alias_method_chain的等价物。

我看到alias_method_chain不再存在于Rails 3.0.0中。 http://api.rubyonrails.org/不报告它和;rails console报告它是undefined local variable or method

另见 – https://rails.lighthouseapp.com/projects/8994/tickets/285-alias_method_chain-limits-extensibility#ticket-285-20

更新:正如@ecoologic在评论中指出的, alias_method_chain仍然存在于Rails 3.1.1中。