Rails 3:a​​lias_method_chain还在使用吗?

时间:2010-09-11 03:55:30

标签: ruby-on-rails ruby

我刚刚阅读了关于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中的宝石/插件的最佳做法?

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_chainhttp://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中。