Почему настройка локали в Rails действует как глобальная (при использовании Thin)? - PullRequest
19 голосов
/ 13 февраля 2012

Я только что понял, что рекомендуемый Rails способ установки локали в вашем контроллере

before_filter :set_locale

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

устанавливает локаль глобально.Приведенный выше код работает, но мне интересно, действительно ли это default_locale по умолчанию, если вам нужно вводить его явно?

Что я ожидаю, так это иметь локаль для запроса (как у нас есть сеанс для запроса) и делатьчто-то вроде:

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

И если I18n.default_locale используется по умолчанию в противном случае.В идеале это будет соответствовать необязательной локали в пути:

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

На данный момент, если по какой-то причине я пропускаю настройку локали в каком-либо действии, она использует локаль, установленную в предыдущем запросе, который может быть от другого пользователя!

И нет ли потенциального состояния гонки, поскольку один запрос может изменить глобальный I18n.locale, в то время как другой запрос (установив другой языковой стандарт до этого) находится в середине рендеринга?


ОБНОВЛЕНИЕ: Некоторые подробности, которые я нашел на данный момент, из документа I18n:

Устанавливает псевдоглобально текущую локаль, т. Е. В хеше Thread.current def locale = (locale)

Теперь я хочу понять, является ли каждый запрос отдельным потоком.


ОБНОВЛЕНИЕ 2: См. Мой ответ для объяснения.

Ответы [ 2 ]

13 голосов
/ 18 декабря 2012

Итак, теперь окончательный ответ. TL; DR Настройка локали действует как глобальная, только если вы используете многопоточные веб-серверы, такие как Thin и Puma.

Как я уже говорил, I18n.locale=

Наборытекущая локаль псевдоглобально, то есть в хэше Thread.current

Так что предполагается, что это для каждого запроса, и он работает таким же образом в Webrick и Unicorn.

Ноесли вы используете многопоточный веб-сервер, такой как Thin или Puma, кажется, что поток живет дольше и значение сохраняется для будущих запросов, пока не будет явно изменено.Я узнал об этом из нового драгоценного камня Стива Клабника request_store :

Если вам нужно глобальное состояние, вы, вероятно, достигли Thread.current.

<...>

Таким образом, люди используют такие причудливые многопоточные веб-серверы, как Thin или Puma.Но если вы используете Thread.current, и вы используете один из этих серверов, будьте осторожны!Значения могут сохраняться дольше, чем вы ожидаете, и это может привести к ошибкам.

2 голосов
/ 13 февраля 2012

Рекомендованный выше код не устанавливает глобальную локаль, он устанавливает ее по запросу.

before_filter :set_locale

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

Код обычно помещается в BaseController, поэтому перед отображением каждой страницы он запускается и устанавливается. Условия гонки отсутствуют, поскольку каждая страница будет вызывать этот код, и там будет рассчитываться локаль I18n. Вы можете расширить это, скажем, ищет языковой стандарт для пользователей, чем языковой стандарт для сеанса, чем параметры запроса, чем использует английский.

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

Другими словами, если вы установите local на одной странице, скажем, в домашнем контроллере на немецкий и попали в контроллер панели мониторинга, вы увидите язык по умолчанию (английский). Поскольку изменения не являются глобальными. Именно поэтому код размещается в базовом контроллере. Надеюсь, это имеет смысл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...