Skip to content

[Guides] Bug in "Managing the Locale across Requests" section with Puma #34043

@tegon

Description

@tegon

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:

I18n.locale=

i18-global-puma

I18n.with_locale

i18-with-locale-puma

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 the en 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 an around_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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions