2012-05-06 15 views
19

Desidero utilizzare gli assistenti familiari dei binari, ma con funzionalità leggermente alterata. Il mio modo di vedere, voglio essere in grado di fare qualcosa di simile:Sostituisci gli helper dei binari con accesso all'originale

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 

Il mio modo di vedere, ho tre opzioni:

  1. scimmia patching: riaprire il modulo di rotaie di supporto . Se il team delle rotaie cambia mai il nome del loro modulo helper, il mio codice diventa una fonte di fragilità. Non insormontabile, ma non ideale.
  2. Utilizzare nomi di metodi diversi: Provare a rimanere sull'interfaccia dei binari comuni può essere la mia rovina. Le mie modifiche potrebbero diventare fonte di confusione per altri sviluppatori
  3. Metodi di scollegamento (nuovo): Non sono sicuro se questo funzionerebbe o se avrebbe gli stessi svantaggi di 1. Effettuerà una ricerca, ma potrebbe essere una buona soluzione punto di partenza.

Quindi la domanda qui è, sono bloccato con una di queste soluzioni sub-ottimali, o c'è un altro modo che non ho considerato? Se vado per l'opzione 3, c'è un modo per farlo senza affrontare direttamente il modulo helper rails?

(Nota:. Ho rimosso il contesto, in quanto aggiunge nulla alla domanda)

risposta

30

C'è un modo migliore rispetto a qualsiasi delle opzioni elencate. Basta usare super:

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

Override stylesheet_link_tag in AwesomeHelper farà in modo che, quando viene invocata stylesheet_link_tag, Ruby si incontrano nel percorso metodo di ricerca prima che colpisca ActionView::Helpers::AssetTagHelper. Se @be_awesome è true, si arriva a prendere in carico e interrompere le cose proprio lì, e in caso contrario, la chiamata a super senza parentesi passerà in modo trasparente attraverso tutti gli argomenti fino all'implementazione di Rails. In questo modo non devi preoccuparti del core team di Rails che muove le cose intorno a te!

+0

Sai cosa ... è così folle e ovvio, sto provando a tormentarmi per capire perché Ho pensato che non avrebbe funzionato! Ci proverò stasera e, se funziona, avrò parole severe con il mio cervello, probabilmente coinvolgendo un muro di mattoni. Dopo, ovviamente, accettando la tua risposta ...: D – user208769

+1

@ user208769 Hehehe. È fantastico. Nella migliore delle ipotesi, i metodi di override in questo modo sono generalmente preferibili in qualsiasi circostanza. [Class # ancestors] (http://ruby-doc.org/core-1.9.3/Module.html#method-i-estestori) può essere davvero utile per capire un buon posto nel metodo di ricerca del metodo per il metodo di hijack dispacciamento (o dove il modulo personalizzato con l'override deve essere incluso al meglio). – Cade

+0

Cosa? :) Stai scherzando! Questo è un trucco ENORME! Il tuo modo di includere l'assistente in OGNI classe che include AssetTagHelper. Il tempo vola e tu o qualcun altro puoi dimenticarti della necessità di includere la tua patch. Devi solo includere AssetTagHelper e iniziare a chiedermi: perché il mio sito ora ha un aspetto diverso? È buono quando tu e il produttore di patch siete la stessa persona. Ma cosa succede se no? – jdoe

6

Non faccio uso di questo gioiello, così ti risponderò in modo più generico.

Supponiamo di voler registrare le chiamate all'help link_to (sì, un esempio forzato, ma mostra l'idea). La ricerca in API ti consente di comprendere che link_to si trova all'interno del modulo ActionView::Helpers::UrlHelper. Così, si crea un po 'di file nel, diciamo, config/initializers directory con i seguenti contenuti:

# 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 

Il nucleo di questa funzionalità - alias_method_chain (cliccabile). Utilizzalo DOPO aver definito il metodo xxx_with_feature.

+0

Sì, questo approccio è stato quello che volevo dire da "Monkey patching moduli rotaie specifici" - che funziona bene, ma se rotaie nucleo cambiano i loro nomi dei moduli, le mie pause codice. Questo potrebbe non essere un grosso problema, ma sono curioso di vedere se ci sono altre soluzioni. Detto questo, mi ero dimenticato di alias_method_chain, grazie per avermelo ricordato! – user208769

+0

P.S: ho aggiornato la domanda per rimuovere l'esempio della gemma. Speriamo che questo layout sia meno confuso! Grazie. – user208769

+0

Il rischio è sempre lì! Se ti preoccupi di "alias_method_chain', non dovresti: esiste dalla versione 1.4.0 (anno 2007). Se ti preoccupi di altre parti del tuo programma, assicurati una copertura di test decente. – jdoe

2

Vorrei davvero incoraggiarvi a considerare la vostra opzione n. 2, ignorando il comportamento dei metodi di rotaie in un modo ovvio per il chiamante.

Il tuo nuovo metodo deve essere chiamato awesome_stylesheet_link_tag in modo che altri sviluppatori Rails possano leggere il tuo codice e porre la domanda "Che cosa c'è di così meraviglioso nel tag del link?".

Come piccola modifica è possibile eseguire l'override ma passare :awesome => true come argomento in modo che almeno abbiano la minima idea che qualcosa è in corso.

La modifica del comportamento di un metodo ampiamente utilizzato come stylesheet_link_tag crea un potenziale malinteso futuro in cui nessuno è necessario.

+0

Grazie per l'input. Mentre di solito sono d'accordo, in questo caso particolare penso che la coerenza sia giustificata - lo sto facendo per usare wicked_pdf e avere esattamente lo stesso codice per generare un PDF o una pagina web. Mentre wicked_pdf di default fa come dici tu (wicked_pdf_stylesheet_link_tag), per me richiede troppe ripetizioni, e penso che sia accettabile aspettarsi che la funzionalità possa cambiare se stai generando un PDF. Ma fai un buon punto e alcuni consigli pratici, quindi grazie. – user208769

4

Prova utilizzando 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 
Problemi correlati