-
Notifications
You must be signed in to change notification settings - Fork 21.9k
Description
Context
I was reviewing a colleague's pull request when I saw the following code:
before_action :set_locale
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
I commented that since we use Puma, this could cause issues because we're changing a global value in a not thread-safe way. What might happen is that while one request changes the locale, another using I18n.locale
directly might get the changed locale instead of the default one - which can be assumed as the value we'll get when we do not change the locale in a request.
I know that because I've seen this I18n issue before.
An approach that would work is to use I18n.with_locale
:
around_action :switch_locale
def switch_locale(&action)
locale = params[:locale] || I18n.default_locale
I18n.with_locale(locale, &action)
end
He answered that he got this solution straight from the Rails guides, in the following section: https://guides.rubyonrails.org/i18n.html#managing-the-locale-across-requests.
This might look obvious - a global value is changed, so it will affect other requests too - but it might not be clear to everyone, especially beginners. And since Puma is a very popular choice these days to work with Rails, I decided to open this issue to see if you're willing to accept a patch to change the guides.
Sample repository
I created a sample repository where this can easily be tested. The relevant files are https://github.com/tegon/rails-guides-locales-bug/blob/master/config/environments/development.rb#L62, https://github.com/tegon/rails-guides-locales-bug/blob/master/app/controllers/pages_controller.rb and
https://github.com/tegon/rails-guides-locales-bug/blob/master/app/controllers/locales_controller.rb
If you just want to see it in action, there are some gifs below too:
Steps to reproduce
- Clone the repository: https://github.com/tegon/rails-guides-locales-bug
- Run
bin/setup
- Rails
bin/rails server
- Fire multiple requests that changes
I18n.locale
:for i in
seq 100; do; curl http://localhost:3000/home\?locale\=pt-BR; echo ""; done
- Fire multiple requests to show the value of
I18n.locale
:for i in
seq 100; do; curl http://localhost:3000/locale ; echo ""; done
- Check whether the values of the second requests show some
pt-BR
between theen
values
System configuration
Rails version: 5.2.1
Ruby version: 2.5.0
Proposed solution
The way I see it we could either:
- Change the docs to use the
I18n.with_locale
with anaround_action
- Keep the current example and add notes to warn that it might leak the local in multi-threaded environments, alongside the
I18n.with_locale
example.
Please let me know your thoughts on it. I will be happy to send a pull request for this if you agree with this. Thanks!