Separate session per URI under Rails 3.1 and Phusion Passenger

Like PHP or any other web programming language, you can deploy multiple instances of the same Rails application on the same server. One reason for having multiple instances on the same server would be the need for multiple exclusive data sets while saving costs on hardware and administration from having to maintain multiple boxes. All you need to do is duplicate the application files, change your database configuration in each directory, and configuring some virtualhost settings.

If your Rails application is deployed with Phusion Passenger, their documentation provides simple instructions on how to get this set up for both a virtual host’s root or stub URIs on one virtualhost.

That’s great, but here’s a problem

When following the instructions for a stub URI, I was easily able to get multiple instances of my application running on the same box. However, I found that user sessions between the instances were stepping on each other. My application allows authentication and stores username and password in the database using the Rails 3.1 built in secure_password authentication facility. Since each instance has its own database, each instance has its own set of users with their own IDs in the databases, meaning user ‘dan’ in instance 1 may not have the same ID as user ‘dan’ in instance 2 depending on the order in which they were created. This is an annoyance to the user as well as a serious security issue. Users should be able to see their sessions and data only. Granted, in my particular application, the user data is not that important, but session management should be done correctly nonetheless.

Solution

The easiest way to get around this problem is to change the name of the cookie for each application instance. Enter session_store.rb in your config/initializers/ application directory. Options in this file specify how your session is stored by the application. My default configuration looked like this:

MyAwesomeApp::Application.config.session_store :cookie_store, key: '_myawesomeapp_session'

This line specifies that our rails application should use cookies for session storage (:cookie_store) and that the name of the cookie as used by the application will be ‘_myawesomeapp_session’. What this means is that for every deployment of my application, the cookie’s name was the same ‘_myawesomeapp_session’ so all instances were using the same session.

To make our cookie name unique for each instance and therefore separate our sessions for each instance of the application, we just need to change the value of ‘key’. One way to do this dynamically without having to change this file manually on each instance is to use the name of the directory where the Rails application lives. Since session_store.rb file is a ruby file, we can put some ruby code in it:

MyAwesomeApp::Application.config.session_store :cookie_store, {
         :key => Rails.root.split[1].to_s + '_session',
}

Explanation

Running ‘Rails.root’ gives the full path on the web server’s filesystem to your application. If we run split and pull just parameter number one, converting its value to a string, we then have the name of the bottom level directory where the application lives, which should hopefully be different for every instance. So if out application lived at ‘/usr/rails/myawesomeapp1’, this code would set the cookie name to ‘myawesomeapp1_session’, ‘/usr/rails/myawesomeapp2’ will set it to ‘myawesomeapp2_session’ and so on, preventing our sessions from stepping on each other.

References

Phusion Passenger: Deploying to a stub URI
ActiveModel::SecurePassword

Leave a Reply

Your email address will not be published.