17

Ho appena realizzato che il modo Rails consigliato per impostare locale nel controllorePerché le impostazioni locali in Rails agiscono come globali (quando si utilizza Thin)?

before_filter :set_locale 

def set_locale 
    I18n.locale = params[:locale] || I18n.default_locale 
end 

imposta il locale a livello globale. Il codice sopra funziona, ma mi chiedo se il valore predefinito sia default_locale se è necessario digitarlo in modo esplicito?

Quello che mi aspetto è quello di avere un locale per richiesta (come abbiamo sessione per ogni richiesta) e di fare qualcosa di simile:

def set_locale 
    locale = params[:locale] if params[:locale] 
end 

E avendo I18n.default_locale utilizzato di default altrimenti. Ciò corrisponde idealmente il locale opzionale nel percorso:

# config/routes.rb 
scope "(:locale)", :locale => /en|nl/ do 
    resources :books 
end 

Per ora se per qualche motivo mi salta impostazioni locali in qualche azione che utilizza l'impostazione internazionale impostato nella precedente richiesta che potrebbe provenire da un altro utente!

E non c'è una potenziale condizione di competizione in quanto una richiesta può cambiare il I18n.locale globale mentre un'altra richiesta (che ha impostato un'altra località prima) è nel mezzo del rendering?


UPDATE: Alcuni dettagli ho trovato per ora, dall'aria documentstion I18n:

Imposta locale corrente pseudo-globalmente, cioè nella hash Thread.current def locale = (locale)

Ora voglio capire se ogni richiesta è una discussione separata.


UPDATE 2: vedi la mia risposta per la spiegazione.

risposta

12

Quindi ora la risposta finale. TL; DR Le impostazioni internazionali funzionano come globali solo quando si utilizzano server Web con thread, come Thin e Puma.

Come accennato, I18n.locale=

Imposta locale corrente pseudo-globale, cioè nella filettatura.hash attuale

Quindi dovrebbe essere per richiesta e funziona in questo modo in Webrick e Unicorn.

Ma se si utilizza un server Web filettato come Thin o Puma, sembra che il thread duri più a lungo e il valore venga conservato per le richieste future, finché non viene modificato esplicitamente. Dove ho imparato è dal gioiello di nuovo Steve Klabnik request_store:

Se avete bisogno di stato globale, probabilmente avete raggiunto per Thread.current.

<...>

Quindi le persone stanno usando quei fantasia threaded server web, come sottile o Puma. Ma se usi Thread.current e usi uno di quei server, fai attenzione! I valori possono rimanere più a lungo di quanto ci si aspetti e ciò può causare bug.

+0

Sto avendo lo stesso identico problema, ma sto usando Unicorn! Qualche idea su come risolvere questo? grazie –

+0

Penso che quando dici "I18n.set_locale", in realtà intendi "I18n.locale =" giusto? http://www.rubydoc.info/github/svenfuchs/i18n/I18n/Config:locale= – lulalala

+0

Hai ragione, grazie per la correzione. – khustochka

2

Il codice consigliato riportato sopra non imposta le impostazioni internazionali in tutto il mondo lo imposta su richiesta.

before_filter :set_locale 

def set_locale 
    I18n.locale = params[:locale] || I18n.default_locale 
end 

Il codice è in genere posto in BaseController, quindi prima che ogni pagina venga visualizzata, viene attivata e impostata. Non ci sono condizioni di gara poiché ogni pagina attiverà questo codice e lì verrà calcolata la localizzazione I18n. È possibile espandere questo aspetto, ad esempio, per cercare le impostazioni internazionali degli utenti, rispetto alle impostazioni locali della sessione, rispetto ai parametri di richiesta, anziché utilizzare l'inglese.

def set_locale 
    I18n.locale = @user.locale || session[:locale] || params[:locale] || :en 
end 

In altre parole se si imposta locale in una pagina diciamo controller a casa per il tedesco e avuto modo di controllore cruscotto si vedrà lingua predefinita (inglese). Poiché il cambiamento non è globale. Questo è il motivo per cui il codice viene inserito nel controller di base. Spero che abbia senso.

+1

'I18n' è un modulo globale e' I18n.locale = 'cambia il suo stato. Sono d'accordo che il modo consigliato di impostare esplicitamente la locale per ogni richiesta tramite 'before_filter' funziona come previsto in generale. Ancora mi chiedo se le richieste di Rails possono essere eseguite simultaneamente in thread diversi - se sì, vedo che la richiesta 1 imposta 'I18n.locale', quindi richiede 2 set diversi' I18n.locale', quindi 1 inizia il rendering usando la nuova (errata) locale. Scusa se ho sbagliato la risposta. – khustochka

Problemi correlati