que - Ruby on Rails: alias_method_chain, ¿qué es exactamente?
ruby on rails tutorial (4)
He intentado leer varias publicaciones de blog que intentan explicar alias_method_chain y las razones para usarlo y no usarlo. En particular, presté atención a:
http://weblog.rubyonrails.org/2006/4/26/new-in-rails-module-alias_method_chain
y
http://yehudakatz.com/2009/03/06/alias_method_chain-in-models/
Todavía no veo ningún uso práctico para alias_method_chain. ¿Alguien podría explicar algunas cosas?
1 - ¿Todavía se usa?
2 - ¿Cuándo usarías alias_method_chain y por qué?
¿se usa para nada?
Parece que sí . Es una práctica común entre los desarrolladores de Rails
¿Cuándo usarías alias_method_chain y por qué?
A pesar de las advertencias, alias_method_chain sigue siendo la principal estrategia utilizada cuando se inyecta la funcionalidad a un método existente, al menos en Rails 2.xy es seguido por muchas personas que lo amplían. Yehuda debería eliminar alias_method_chain de rails 3.0 para que diga de sus publicaciones y comentarios en las entradas de Rails. Todavía es utilizado por muchas extensiones que agregan un comportamiento personalizado en ciertos puntos de la ejecución, como registradores, reporteros de errores, evaluación comparativa, inyección de datos, etc.
OMI, la mejor alternativa es incluir un módulo, por lo que tiene decoración sobre delegación. (Por ejemplo, siga el ejemplo 4 en esta publicación ). De esta forma, puede modificar los objetos incluso individualmente si lo desea, sin contaminar los métodos de la clase. La desventaja de esto es que la cadena de búsqueda de métodos aumenta para cada módulo que se inyecta, pero de todos modos es de lo que se trata los módulos.
Una pregunta muy interesante, eche un vistazo a lo que otras personas piensan al respecto.
1 - ¿Todavía se usa?
Aparentemente sí, alias_method_chain()
todavía se usa en Rails (a partir de la versión 3.0.0).
2 - ¿Cuándo usarías alias_method_chain y por qué?
( Nota: lo siguiente se basa principalmente en la discusión de alias_method_chain()
en Metaprogramming Ruby por Paolo Perrotta, que es un excelente libro que debes tener en tus manos).
Comencemos con un ejemplo básico:
class Klass
def salute
puts "Aloha!"
end
end
Klass.new.salute # => Aloha!
Ahora supongamos que queremos rodear a Klass#salute()
con el comportamiento de registro. Podemos hacer eso que Perrotta llama un alias alrededor :
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()
un nuevo método llamado salute_with_log()
y lo alias para salute()
. El código que solía llamar a salute()
todavía funciona, pero también obtiene el nuevo comportamiento de registro. También definimos un alias para el salute()
original salute()
, por lo que aún podemos saludar sin iniciar sesión:
Klass.new.salute_without_log # => Aloha!
Entonces, el salute()
ahora se llama salute_without_log()
. Si queremos iniciar sesión, podemos llamar a salute_with_log()
o a salute()
, que son alias del mismo método. ¿Confuso? ¡Bueno!
Según Perrotta, este tipo de alias es muy común en Rails:
Mira otro ejemplo de Rails resolviendo un problema a su manera. Hace algunas versiones, el código de Rails contenía muchas instancias de la misma expresión idiomática: se usaba Around Alias (155) para agregar una función a un método, y la versión anterior del método se
method_without_feature()
a algo comomethod_without_feature()
. Además de los nombres de los métodos, que cambiaban cada vez, el código que hacía esto siempre era el mismo, duplicado por todos lados. En la mayoría de los idiomas, no puede evitar ese tipo de duplicación. En Ruby, puedes rociar un poco de metaprogramación mágica sobre tu patrón y extraerlo en su propio método ... y así nacióalias_method_chain()
.
En otras palabras, usted proporciona el método original, foo()
, y el método mejorado, foo_with_feature()
, y termina con tres métodos: foo()
, foo_with_feature()
y foo_without_feature()
. Los primeros dos incluyen la función, mientras que el tercero no. En lugar de duplicar estos alias por todos alias_method_chain()
, alias_method_chain()
provisto por ActiveSupport hace todo el alias por usted.
No estoy seguro si ha pasado de moda con Rails 3 o no, pero todavía se usa activamente en versiones anteriores.
Se usa para inyectar alguna funcionalidad antes (o después) de llamar a un método, sin modificar ningún lugar que llame a ese método. Mira este ejemplo:
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
¡Es una adición a ActionMailer para permitir el intercambio de la configuración SMTP en cada llamada para deliver!
. ¡Llamando alias_method_chain
puedes definir un método deliver_with_switchable_smtp!
en el que haces tus cosas personalizadas, y llama a deliver_without_switchable_smtp!
a partir de ahí cuando hayas terminado.
alias_method_chain
el viejo deliver!
a su nuevo método personalizado, por lo que el resto de su aplicación ni siquiera sabe deliver!
ahora también hace tus cosas personalizadas.
alias_method_chain
ha quedado en desuso en Rails 5 a favor de Module#prepend
.
Solicitud de extracción: https://github.com/rails/rails/pull/19434
Registro de cambios: https://github.com/rails/rails/blob/b292b76c2dd0f04fb090d49b90716a0e6037b41a/guides/source/5_0_release_notes.md#deprecations-4