2009-02-24 20 views
43

La gema will_paginate se rompe en mi versión de Oracle. El método predeterminado paginate_by_sql en el módulo WillPaginate es insertar un 'AS' 'extra en una consulta y hacer que falle.Anulando un método de módulo de una gema en Rails

El código en sí se soluciona fácilmente, pero no estoy seguro de la mejor manera de que Rails recoja mi cambio.

No quiero cambiar el código en la gema, ya que eso dejará mi código dañado en otras máquinas.

intenté crear un archivo lib/test.rb que contiene:

module WillPaginate 
    def paginate_by_sql 
    (my code goes here) 
    end 
end 

y requiriendo desde environment.rb, pero no es recoger mis cambios. También traté de requerirlo desde los controladores/application.rb, pero de nuevo, no recogiendo mis cambios.

Temporalmente, lo tengo que trabajar anulando el método dentro del modelo específico en sí, pero esto es un poco complicado, y significa que no puedo usarlo en ninguno de los otros modelos de este proyecto.

Estoy seguro de que hay una manera fácil de hacerlo, pero no estoy teniendo suerte siguiendo su rastro con Google.

+0

Si el código de la gema está roto, seguramente está roto en todas partes? ¿Has registrado un error en el proyecto? http://wiki.github.com/mislav/will_paginate/reportbugs –

+0

Todavía no - el error está en un bloque manejando casos específicos de Oracle. La causa es porque estoy usando el adaptador con oráculo mejorado (en lugar del oráculo u oci). Creo que la mayoría de las personas están usando el adaptador Oracle y no se encontrarán con esto) En cualquier caso, se registrará el error de todos modos. –

Respuesta

27

lo que está haciendo el trabajo voluntad, pero su código necesita tener este aspecto:

module WillPaginate 
    module Finder 
    module ClassMethods 
     def paginate_by_sql(sql, options) 
     # your code here 
     end 
    end 
    end 
end 

En otras palabras, entra en finder.rb, borrar todo excepto las cabeceras de los módulos y el método que desea anular , luego guárdelo en un archivo en lib e inclúyalo en environment.rb. ¡Voila, parche de mono instantáneo!

+0

Cool. Gracias. Eso hizo el truco =) –

+13

esto debería estar en el inicializador 'config/initializers' - ¡no ponga esto en el archivo' environment.rb'! – Tilo

61

Una solución más concisa:

WillPaginate::Finder::ClassMethods.module_eval do 
def paginate_by_sql sql, options 
    # Your code here 
end 
end 

Coloque el código en un fichero de inicialización en config/inicializadores. Este es el lugar correcto para colocar el código que se debe ejecutar cuando se carga el entorno. También organiza mejor el código, haciendo que la intención de cada archivo sea más clara, por lo que los errores serán más fáciles de rastrear. ¡No desordene el medio ambiente! Rb!

+0

Caso de esquina interesante si la clase subyacente se carga a través de 'autocarga ': http://stackoverflow.com/questions/8736451/override-a-method-inside-a-gem-from-another-gem – Tilo

+1

Bastante bien. En el nuevo 'paginate_by_sql', ¿puedo acceder a su versión anterior? ¿Puedo llamar algo como 'super (sql, options)'? –

38

Ok, voy a hacer que esto sea más fácil para las personas como yo que vienen y todavía luchan un poco después de leer las otras respuestas.

Primera encontrar el código que desea cambiar en el repositorio GitHub mediante la búsqueda de la línea de código (se puede encontrar fácilmente esta usando pry) que desea cambiar en la gema, y ​​luego seleccionando Code en el izquierda en lugar de Issues

enter image description here

enter image description here

Siguiente Copiar el conte nt del módulo que desea cambiar y colocarlo en un archivo .rb acertadamente llamado dentro de su carpeta config/initializers.He aquí un ejemplo:

module Forem 
    module TopicsHelper 
    def link_to_latest_post(post) 
     text = "#{time_ago_in_words(post.created_at)} #{t("ago_by")} #{post.user}" 
     link_to text, forum_topic_path(post.topic.forum, post.topic, :anchor => "post-#{post.id}") 
    end 
    end 
end 

Ahora, cambie a:

Forem::TopicsHelper.module_eval do 
    def link_to_latest_post(post) 
    text = "#{time_ago_in_words(post.created_at)} #{t("ago_by")} #{post.user}" 
    link_to text, forum_topic_path(post.topic.forum, post.topic, :anchor => "post-#{post.id}") 
    end 
end 

Ahora, realice los cambios adicionales en el código y reinicie el servidor.

Away you go!

+0

¿Sería capaz de llamar al método original de esta manera o tiene alias_method_chain (en Rails de todos modos) para eso? – Machisuji

+0

Método original – Abram

+1

Gracias @Abram! ¡Esto fue muy útil! – KavitaC

Cuestiones relacionadas