We have a Ruby on Rails application that has the concept of multiple brands / multiple domains. The look and feel changes based on the requested domain. In addition, the site currently supports two languages. English by default, and French as an option.
Before we updated it to support more than one brand, URLs were either the default (English),
branddomain.com/page-slug
or
branddomain.com/fr/page-slug
if a visitor chose to view in French.
We achieved this using the pattern
scope '(:locale)', locale: /en|fr/ do
# various URL handler definitions
end
in routes.db
When we started supporting multiple brands we wanted to take advantage of Rails’ locale and use locales such as brandone-en
or brandtwo-en
or brandone-fr
or brandtwo-fr
.
This allows us to use ERB files defined with a brand as well as translation file relying on fallbacks.
To prevent the URL from showing the brand locale in we used the following method on each request
def set_locale(&action)
original_locale = I18n.default_locale
I18n.default_locale = "en-#{site.slug}"
# set to locale in param if present otherwise provide language options
# and set locale from set of options available best suited for the browser
begin
I18n.with_locale(params[:locale] || I18n.default_locale, &action)
rescue I18n::InvalidLocale
not_found
end
ensure
I18n.default_locale = original_locale
end
The problem we found when deploying to production is that I18n.default_locale is not thread safe. It’s shared between all threads and therefore simultaneously requests will set the default_locale to the wrong brand for another visitor. To get around this we have to reduce Puma to a single thread with high concurrency. Not ideal.
If anyone has experience with this kind of setup your advice would be appreciated.
1