我刚刚阅读了关于Rails 3的Gems / Plugin开发,并在this post上运行,表示不再使用alias_method_chain。我可以看到该方法仍然存在于activesupport-3.0.0 / lib / active_support / core_ext / module / aliasing.rb中。
我是否还应该在Rails 3中使用alias_method_chain?
this是否仍然反映了想要修改ActiveRecord的Rails 3中的宝石/插件的最佳做法?
答案 0 :(得分:57)
不,它已被模块中的方法覆盖和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
<{3}}的Ryan Bates谈到Railscasts。我建议观看它,以及他的其他截屏视频。他们有能力将针织祖母变成Rails大师。
PS:为了纠正原始答案中的基本错误,信用证转到how this is used in the Rails Routing code。感谢。
答案 1 :(得分:19)
通常,模块永远不能覆盖类中的方法 它包括在内。这是因为模块包含工作正常 喜欢子类化。超类不能覆盖其子类' 方法,或者你也不期望它。
当模块包含在类中时,将插入模块
就在班级祖先连锁课堂之后。调用
来自类的super
将调用模块的实现。
class Something
module PreExtension; end
module PostExtension; end
include PreExtension
include PostExtension
end
Something.ancestors # => [Something, Something::PostExtension, Something::PreExtension, Object, Kernel]
每当在Something
上调用方法时,Ruby都会查看
此列表按顺序并调用它找到的第一个实现。
如果实现调用super
,它会一直查找并查找
下一个。
这意味着后面包含的模块优先于
之前包含的模块,可以调用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
。
答案 2 :(得分:0)
我发现Rails 3.0.0中不再存在alias_method_chain
。 http://api.rubyonrails.org/不报告,rails console
报告undefined local variable or method
。
更新:正如@ecoologic在评论中指出的那样,alias_method_chain
仍存在于Rails 3.1.1中。