Ruby on Rails:alias_method_chain,它究竟做了什么?

我尝试阅读各种博客文章,试图解释alias_method_chain和使用它的原因,而不是使用它。 特别是,我留意到:

http://weblog.rubyonrails.org/2006/4/26/new-in-rails-module-alias_method_chain

http://yehudakatz.com/2009/03/06/alias_method_chain-in-models/

我仍然没有看到alias_method_chain的实际用途。 任何人都可以解释一些事情。

1 – 它还在使用吗?
2 – 你什么时候会使用alias_method_chain,为什么?

1 – 它还在使用吗?

显然是的, alias_method_chain() 仍然在Rails中使用 (从版本3.0.0开始)。

2 – 你什么时候会使用alias_method_chain,为什么?

注意:以下内容主要基于Paolo Perrotta 编写的Ruby编程中的alias_method_chain()的讨论,这是一本很好的书,您应该亲自操作。)

我们从一个基本的例子开始:

 class Klass def salute puts "Aloha!" end end Klass.new.salute # => Aloha! 

现在假设我们想用logging行为来包围Klass#salute() 。 我们可以做Perrotta所谓的别名

 class Klass def salute_with_log puts "Calling method..." salute_without_log puts "...Method called" end alias_method :salute_without_log, :salute alias_method :salute, :salute_with_log end Klass.new.salute # Prints the following: # Calling method... # Aloha! # ...Method called 

我们定义了一个名为salute_with_log()的新方法,并将其别名为salute() 。 用来调用salute()的代码仍然有效,但它也获得了新的日志logging行为。 我们还定义了原始salute()的别名salute() ,所以我们仍然可以在不login的情况下敬礼:

 Klass.new.salute_without_log # => Aloha! 

所以, salute()现在被称为salute_without_log() 。 如果我们要logging日志,我们可以调用salute_with_log()salute() ,它们是同一个方法的别名。 困惑? 好!

根据Perrotta的说法,这种别名在Rails中非常常见:

看看Rails以自己的方式解决问题的另一个例子。 几个版本之前,Rails代码包含了许多相同习惯用法的实例:使用Around Alias (155)将一个特性添加到一个方法,并且旧版本的方法被重命名为类似method_without_feature() 。 除了每次更改的方法名称之外,执行此操作的代码始终是相同的,重复遍布整个地方。 在大多数语言中,你无法避免这种重复。 在Ruby中,你可以在你的模式中添加一些元编程魔法,并将其提取到自己的方法中,从而诞生了alias_method_chain()

换句话说,您提供了原始方法foo()和增强方法foo_with_feature() ,并最终提供了三个方法: foo()foo_with_feature()foo_without_feature() 。 前两个包含该function,而第三个则不包含该function。 ActiveSupport提供的alias_method_chain()不是全部复制这些别名,而是为您完成所有别名。

我不确定Rails 3是否已经过时了,但在之前的版本中,它仍然是积极使用的。

您可以在调用方法之前(或之后)使用它来注入某些function,而不必修改任何调用该方法的地方。 看到这个例子:

 module SwitchableSmtp module InstanceMethods def deliver_with_switchable_smtp!(mail = @mail) unless logger.nil? logger.info "Switching SMTP server to: #{custom_smtp.inspect}" end ActionMailer::Base.smtp_settings = custom_smtp unless custom_smtp.nil? deliver_without_switchable_smtp!(mail = @mail) end end def self.included(receiver) receiver.send :include, InstanceMethods receiver.class_eval do alias_method_chain :deliver!, :switchable_smtp end end end 

这是ActionMailer的补充,允许在每次调用中交换SMTP设置以deliver! 。 通过调用alias_method_chain你可以定义一个方法deliver_with_switchable_smtp! 在其中你做你的自定义的东西,并调用deliver_without_switchable_smtp! 从那里当你完成。

alias_method_chain别名旧的deliver! 到你的新的自定义方法,所以你的应用程序的其余部分甚至不知道deliver! 现在也做你的自定义的东西。

在Rails 5中, alias_method_chain已经被弃用,因而支持Module#prepend

拉请求: https : //github.com/rails/rails/pull/19434

更新日志: https : //github.com/rails/rails/blob/b292b76c2dd0f04fb090d49b90716a0e6037b41a/guides/source/5_0_release_notes.md#deprecations-4

它是用在所有?

似乎如此 。 这是Rails开发人员的惯常做法

你什么时候会使用alias_method_chain,为什么?

尽pipe有警告,alias_method_chain仍然是在向现有方法注入function时使用的主要策略,至less在Rails 2.x中,随后是许多人将其扩展。 耶胡达应该从Rails 3.0中删除alias_method_chain,以便在他的post和Rails票据中留言。 它仍被许多扩展使用,这些扩展在执行的某些点添加自定义行为,例如logging器,错误logging器,基准testing,数据注入等。

国际海事组织,最好的select是包括一个模块,因此你有装饰超过委托。 (例如,在本文中按照示例4)。 这样,如果你愿意的话,你甚至可以单独改变对象,而不会污染类的方法。 不利的一面是,你注入的每个模块的方法查找链会增加,但是这就是模块。

非常有意思的问题,会看看别人怎么看。