2012-05-06 18 views
19

Quiero utilizar los ayudantes familiares de los rieles, pero con una funcionalidad ligeramente alterada. La forma en que lo veo, quiero ser capaz de hacer algo como:Anula los auxiliares de rieles con acceso al original

module AwesomeHelper 
    #... create alias of stylesheet_link_tag to old_stylesheet_link_tag 
    def stylesheet_link_tag(*args) 
    if @be_awesome 
     awesome_stylesheet_link_tag *args 
    else 
     old_stylesheet_link_tag *args 
    end 
    end 
end 

la forma en que lo veo, tengo tres opciones:

  1. mono parches: volver a abrir el módulo de rieles ayudante . Si el equipo de rails cambia alguna vez el nombre de su módulo auxiliar, mi código se convierte en una fuente de fragilidad. No insuperable, pero no ideal.
  2. Use nombres de métodos diferentes: Tratar de mantener la interfaz de los carriles comunes puede ser mi perdición. Mis cambios pueden convertirse en una fuente de confusión para otros desarrolladores
  3. Métodos de separación (nuevos): No estoy seguro de si esto funcionaría, o si tendría los mismos inconvenientes que 1. Investigaré esto, pero esto podría ser una buena punto de partida.

Así que la pregunta aquí es, ¿estoy atrapado con una de estas soluciones subóptimas, o hay alguna otra forma que no he considerado? Si selecciono la opción 3, ¿hay alguna manera de hacerlo sin dirigirme directamente al módulo de carriles auxiliares?

(Nota:. He quitado el contexto, ya que no añade nada a la pregunta)

Respuesta

30

Hay una manera mejor que cualquiera de sus opciones enumeradas. Sólo tiene que utilizar super:

module AwesomeHelper 
    def stylesheet_link_tag(*sources) 
    if @be_awesome 
     awesome_stylesheet_link_tag *sources 
    else 
     super 
    end 
    end 
end 

Anulación stylesheet_link_tag en AwesomeHelper se asegurará de que, cuando se invoca stylesheet_link_tag, Ruby se encontrará en el camino de búsqueda de métodos antes de que llegue ActionView::Helpers::AssetTagHelper. Si @be_awesome es true, puede hacerse cargo y detener las cosas allí mismo, y si no, la llamada al super sin paréntesis pasará transparentemente por todos los argumentos hasta la implementación de Rails. ¡De esta manera no tienes que preocuparte por el equipo central de Rails moviendo cosas contigo!

+0

¿Sabes qué ... es tan loco obvio, estoy tratando de hacer estallar mis cerebros para averiguar por qué? ¡Pensé que no funcionaría! Voy a intentarlo esta noche y, si funciona, tendré palabras severas con mi cerebro, probablemente con una pared de ladrillos. Después, por supuesto, aceptando su respuesta ...: D – user208769

+1

@ user208769 Hehehe. Eso es genial. Como mejor entiendo, los métodos generales de esta manera son generalmente preferibles en cualquier circunstancia. [Antepasados ​​de la clase #] (http://ruby-doc.org/core-1.9.3/Module.html#method-i-ancestors) pueden ser realmente útiles para encontrar un buen lugar en la ruta de búsqueda de métodos para secuestrar el método despacho (o donde su módulo personalizado con la anulación necesita ser incluido para obtener el mejor efecto). – Cade

+0

¿Qué? :) ¡Tienes que estar bromeando! Este es un GRAN gotcha! De la forma en que debe incluir a su ayudante en CADA clase que incluya AssetTagHelper. El tiempo vuela y tú u otra persona pueden olvidarse de necesitar que se incluya tu parche. Simplemente incluye AssetTagHelper y comienza a preguntarse: ¿por qué mi sitio ahora se ve de manera diferente? Es bueno cuando tú y el parche son la misma persona. Pero, ¿y si no? – jdoe

6

Yo no uso esta joya, así que voy a responder de manera más genérica.

Digamos que desea registrar llamadas a link_to ayudante (sí, ejemplo artificial, pero muestra la idea). Mirar en API le da a entender que link_to se encuentra dentro del módulo ActionView::Helpers::UrlHelper. Así, se crea algún archivo en su, digamos, config/initializers directorio con el siguiente contenido:

# like in config/initializers/link_to_log.rb 
module ActionView::Helpers::UrlHelper 

    def link_to_with_log(*args, &block) 
     logger.info '**** LINK_TO CALL ***' 
     link_to_without_log(*args, &block) # calling the original helper 
    end 

    alias_method_chain :link_to, :log 
end 

El núcleo de esta funcionalidad - alias_method_chain (hacer clic). Úselo DESPUÉS de definir el método xxx_with_feature.

+0

Sí, este enfoque era lo que quería decir con "mono parches módulos carriles específicos" - que funciona bien, pero si carriles núcleo cambian sus nombres de los módulos de código, mis descansos. Esto puede no ser un gran problema, pero tengo curiosidad por ver si hay otras soluciones. Dicho esto, se olvidó de alias_method_chain, ¡gracias por recordarme eso! – user208769

+0

P.S: Se actualizó la pregunta para eliminar el ejemplo de gema. ¡Espero que este diseño sea menos confuso! Gracias. – user208769

+0

¡El riesgo siempre está presente! Si te preocupa 'alias_method_chain', entonces no deberías: existe desde la versión 1.4.0 (año 2007). Si te preocupas por otras partes de tu programa, entonces asegúrate una cobertura de exámenes decente. – jdoe

2

Realmente le animo a que considere su opción n. ° 2, anulando el comportamiento de los métodos de los raíles de una manera que sea obvia para la persona que llama.

Su nuevo método debe llamarse awesome_stylesheet_link_tag para que otros desarrolladores de Rails puedan leer su código y hacer la pregunta "¿Qué tiene de asombroso la etiqueta de enlace?".

Como un cambio más pequeño se puede hacer la anulación, pero pasar en :awesome => true como argumento para que al menos tengan una idea de que algo está en marcha.

Cambiar el comportamiento de un método ampliamente utilizado como stylesheet_link_tag crea un posible malentendido futuro donde no se necesita ninguno.

+0

Gracias por la entrada. Aunque normalmente estoy de acuerdo, en este caso particular, creo que la coherencia está justificada. Hago esto para usar wicked_pdf y tener exactamente el mismo código para generar un PDF o una página web. Mientras wicked_pdf hace de manera predeterminada lo que dices (wicked_pdf_stylesheet_link_tag), requiere demasiada repetición, y creo que es aceptable esperar que la funcionalidad cambie si estás generando un PDF. Pero usted hace un buen punto, y algunos consejos útiles, así que gracias. – user208769

4

Trate de usar alias_method:

module AwesomeHelper 
    alias_method :original_stylesheet_link_tag, :stylesheet_link_tag 

    def stylesheet_link_tag(*sources) 
    if @be_awesome 
     awesome_stylesheet_link_tag *sources 
    else 
     original_stylesheet_link_tag *sources 
    end 
    end 
end 
Cuestiones relacionadas