15

Voglio impostare un attributo di classe quando la mia app Rails si avvia. Richiede l'ispezione di alcuni percorsi, quindi i percorsi devono essere caricati prima dell'esecuzione del mio codice personalizzato. Sto avendo difficoltà a trovare un posto affidabile per agganciare inInizializzatore di rotaie che viene eseguito * dopo * percorsi * vengono caricati?

Questo funziona perfettamente nell'ambiente "test":.

config.after_initialize do 
    Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}" 
end 

Ma non lavoro in ambiente di "sviluppo" (i percorsi sono vuoti)

Per ora sembra che le cose funzionino in modalità sviluppo eseguendo lo stesso codice in config.to_prepare che capisco prima di ogni richiesta. Sfortunatamente l'uso di to_prepare da solo non sembra funzionare in modalità test, quindi la duplicazione.

Sono curioso di sapere perché i percorsi vengono caricati prima di after_initialize in modalità test, ma non in modalità sviluppo. E davvero, qual è il miglior gancio per questo? C'è un solo gancio che funzionerà per tutti gli ambienti?

* suggerimento EDIT *

di mu di ricaricare i percorsi era grande. Mi ha dato un accesso coerente alle rotte all'interno after_initialize in tutti gli ambienti. Per il mio caso d'uso però, penso di aver ancora bisogno di eseguire il codice da to_prepare, poiché imposto un attributo di classe su un modello e i modelli vengono ricaricati prima di ogni richiesta.

Quindi ecco cosa ho finito per fare.

[:after_initialize, :to_prepare].each do |hook| 
    config.send(hook) do 
    User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("\n").scan(/\s\/(\w+)/).flatten.compact.uniq 
    end 
end 

Sembra un po 'complicato per me. Penso che io preferirei fare qualcosa di simile:

config.after_initialize do 
    User.exclude_routes_from_usernames! 
end 

config.to_prepare do 
    User.exclude_routes_from_usernames! 
end 

Ma io non sono sicuro se User è il posto giusto per essere esaminato Rails.application.routes. Immagino di poter fare la stessa cosa con il codice in lib/ma non sono sicuro che sia giusto.

Un'altra opzione è applicare il suggerimento di mu su to_prepare. Funziona, ma sembra esserci un ritardo notevole che ricarica i percorsi su ogni richiesta nel mio ambiente di sviluppo, quindi non sono sicuro che questa sia una buona chiamata, anche se è ASCIUTTA, almeno.

config.to_prepare do 
    Rails.application.reload_routes! 
    User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("\n").scan(/\s\/(\w+)/).flatten.compact.uniq 
end 

risposta

22

È possibile forzare i percorsi da caricare prima di guardare Rails.application.routes con questo:

Rails.application.reload_routes! 

in modo da provare questo nel vostro config/application.rb:

config.after_initialize do 
    Rails.application.reload_routes! 
    Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}" 
end 

Ho fatto cose simili che necessario per controllare i percorsi (per i conflitti con le rotte /:slug) e ho finito per mettere il reload_routes! e il check in uno config.after_initialize come stai facendo.

+0

Grande idea! Si scopre che in realtà stiamo usando questo per la stessa cosa (sto aggiornando un 'class_attribute' chiamato 'User.invalid_usernames' che viene usato come un elenco di esclusione con' validates_exclusion_of'). Penso comunque di avere ancora bisogno di to_prepare per la modalità di sviluppo. Senza di esso, funziona bene alla prima richiesta (ora che sto usando il tuo suggerimento), ma dopo credo che il mio 'User.invalid_usernames = Set.new' lo stia sbavando. Sembra che tu stia usando after_initialize, quindi mi chiedo se ci sia un modo intelligente per aggirare questo? – poochenza

+0

Questa risposta mi ha aiutato molto, quindi lo accetto anche se non l'ho usato (aperto alle critiche se pensi che dovrei pensarci!) Ecco la mia soluzione completa, mi piacerebbe il tuo feedback se hai tempo: http: //stackoverflow.com/a/8713207/1126857 – poochenza

+0

@poochenza: ho usato 'after_initialize' per assicurarmi che non ci siano nuovi conflitti tra le versioni: se aggiungi una route'/pancakes' e la pubblichi due settimane dopo, vuoi sapere se qualcuno ha creato un utente "pancakes" sul sistema di produzione nel frattempo. Quindi confronto i nuovi nomi utente con i percorsi mentre vengono creati o aggiornati i nomi utente. –

2

Se stai cercando di eseguire codice in un inizializzatore dopo le rotte sono caricati, si può provare a utilizzare l'opzione after::

initializer "name_of_initializer", after: :add_routing_paths do |app| 
    # do custom logic here 
end 

È possibile trovare gli eventi di inizializzazione qui: http://guides.rubyonrails.org/configuring.html#initialization-events

+0

Questo inizializzatore non verrà mai eseguito per me nelle guide 4.1.14.1 – nolith

Problemi correlati