2009-02-24 12 views
43

La gemma will_paginate è danneggiata nella mia versione di Oracle. Il metodo predefinito paginate_by_sql nel modulo WillPaginate sta inserendo un 'AS' in una query e causando un errore.Sovrascrittura di un metodo di modulo da una gemma in Rails

Il codice stesso è facilmente risolvibile, ma non sono sicuro del modo migliore per far sì che Rails raccolga la mia modifica.

Non voglio cambiare il codice nella gemma stessa, in quanto ciò lascerebbe il mio codice rotto su altre macchine.

Ho cercato di creare un file lib/test.rb contenente:

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

e che richiedono da environment.rb, ma non è raccogliendo i miei cambiamenti. Ho anche provato a richiederlo dai controller/application.rb, ma ancora una volta, non raccogliendo le mie modifiche.

Temporaneamente, ho avuto modo di funzionare sovrascrivendo il metodo all'interno del modello specifico stesso, ma questo è un po 'un hack, e significa che non posso usarlo su nessuno degli altri modelli in questo progetto.

Sono sicuro che c'è un modo semplice per farlo, ma non ho alcuna fortuna nel rintracciarlo usando Google.

+0

Se il codice della gemma è rotto, sicuramente è rotto ovunque? Hai registrato un bug nel progetto? http://wiki.github.com/mislav/will_paginate/report-bugs –

+0

Non ancora: il bug è in un blocco che gestisce casi specifici di oracle. La causa è perché sto usando l'adattatore oracleenhanced (piuttosto che oracle o oci). Penso che la maggior parte dei ppl stiano usando l'adattatore oracle e non ci stiano addentrando in questo) In breve ci sarà un bug di registrazione. –

risposta

27

ciò che si sta facendo un lavoro volontà, ma il codice deve assomigliare a questo:

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

In altre parole, andare in finder.rb, eliminare tutto tranne le intestazioni di modulo e il metodo che si desidera ignorare , quindi salvare in un file in lib e includere in environment.rb. Voila, patch di scimmia istantanea!

+0

Freddo. Grazie. Questo ha fatto il trucco =) –

+13

dovrebbe essere presente in initializer 'config/initializers' - non inserire questo nel file' environment.rb'! – Tilo

61

Una soluzione più concisa:

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

Mettere il codice in un file di inizializzazione in config/inizializzatori. Questa è la posizione corretta in cui inserire il codice che deve essere eseguito quando viene caricato l'ambiente. Inoltre, organizza meglio il tuo codice, rendendo più chiare le intenzioni di ogni file, quindi i bug saranno più facili da rintracciare. Non ingombrare environment.rb!

+0

Caso d'angolo interessante se la classe sottostante viene caricata tramite 'autoload': http://stackoverflow.com/questions/8736451/override-a-method-inside-a-gem-from-another-gem – Tilo

+1

Piuttosto interessante. Nel nuovo 'paginate_by_sql', posso accedere alla sua versione precedente? Posso chiamare qualcosa come 'super (sql, options)'? –

38

Ok, ho intenzione di renderlo più facile per le persone come me che arrivano e continuano a lottare un po 'dopo aver letto le altre risposte.

Prima trovare il codice che si desidera modificare sul repo github ricercando la riga di codice (si potrebbe facilmente trovare questo usando pry) che si desidera modificare nel gioiello, e quindi selezionando Code sulla a sinistra invece che Issues

enter image description here

enter image description here

Avanti Copiare il conte nt del modulo che si desidera modificare e inserirlo in un file con nome appropriato .rb all'interno della cartella config/inizializzatori.Ecco un esempio:

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 

Ora, modificarla in:

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 

Ora, apportare ulteriori modifiche al codice e riavviare il server.

Via vai!

+0

Sareste in grado di chiamare il metodo originale come questo o avete alias_method_chain (in Rails lo stesso) per quello? – Machisuji

+0

Metodo originale – Abram

+1

Grazie @Abram! Questo è stato molto utile! – KavitaC