My team is working on a multilingual multinational application in Rails (I know this sounds incredibly pushy but bear with me). The application is at susuh.de if you want to have a look at it, but it’s still alpha version.
In practice, this multi-multi-blah-blah means that we want to use both various national domains (like susuh.at, susuh.pl — those links don’t function yet, they are only examples) and various subdomains (like pl.susuh.de or en.susuh.pl). The national domains will filter content only to respective country (so susuh.de will only have content from Germany) and the subdomains will be used to change the default language for the national domain (so if you are an English-speaking person living in Germany, en.susuh.de is your place to go). The subdomain will also be important in multilingual countries like Switzerland.
Trying to implement this scheme we’ve run into problems with cookie domain handling in Rails. And cookie problems lead to session problems for users, like being erroneously logged out or loosing other settings.
Mandatory Cookie-monster reference (you wouldn’t believe how many hits from Google this provides).
It seems that there are two official (normal) ways of handling this — at least that’s what Google says. Either you set your default session options in environment.rb
like this:
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_domain] =
'.susuh.de'
Or you don’t set it at all.
The former lets you set cookies for any subdomain of susuh.de, like pl.susuh.de, but no other domain. The latter sets cookie independently for each subdomain, causing different cookies for pl.susuh.de, en.susuh.de and susuh.pl. Neither is what we really want.
So tell me what you want, what you really really want?
What we really want is to have the same cookie for any subdomain of susuh.eu and a different one for any subdomain of susuh.pl and so on. Nota bene, I’m not talking about a Single Sign-On problem, this is on much more basic level. We tried experimenting with setting DEFAULT_SESSION_OPTIONS
“on the fly” in before_filter
, but found out that this is too late (basically, this sets cookie domain for next request).
Fortunately, all is not lost. If all else fails, start reading code. And that’s what I did. The “entry point” for Rails is defined in dispatcher.rb
file. Glancing over the code, I noticed something new for me: a before_dispatch
callback. Google agreed that this may be a way to go, giving us link to http://m.onkey.org/2007/10/16/dispatcher-callbacks, among others.
Here’s our solution:
require 'dispatcher'
module ActionController
class Dispatcher
def set_session_domain
ApplicationController.session_options.update(
:session_domain => "#{@request.host.gsub(/^[^.]*/, '')}"
)
end
before_dispatch :set_session_domain
end
end