2.3.2 DerailedSay you were using the active_record_store for sessions in Rails 2.2, and you added your own custom column(s) to the default sessions table in your database. You might have done so because you wanted to add, say, the user’s id number to each entry in the sessions table. This would let you do things like quickly and efficiently delete a user’s session.

Unfortunately, when you upgrade to Rails 2.3.2, your session hack will be seriously busted. Cookies will work great, and so will the standard session scheme, but your custom column in the sessions table won’t be updated. Worse yet, you’ll get a lovely error when you do things the old way. The problem is due to 2.3.2’s new “lazy sessions“. In short, unless a session is accessed, it doesn’t load all the session handling stuff. If you don’t want to use sessions, you don’t have to turn them off anymore.

So, that’s great, but your custom sessions table is still broken. There are no solutions posted anywhere that I could find, so I took the liberty of figuring it out myself. Here’s what to do…

In order to have a custom column in your sessions table, you probably did something like creating an empty “session” model (session.rb). Then you added your custom column to the “sessions” table in your DB. For this example, let’s say you added an integer column called “userid” to store a user’s id. You may also have stored just the user’s id in the session hash itself, but accessing the data inside that hash in order to simply delete a user’s session was too slow, mysterious, and painful. So, you committed the cardinal sin and duplicated data in the sessions table.

Well, heck, it’s not your fault that the active_record_store for sessions is so lame! Like most things in Rails, yes, it does “just work”. But it isn’t always so easy to perform simple tasks that should logically be available to you. And as with has_many and belongs_to, sometimes the Rails Way is downright silly, not to mention awful in terms of database efficiency and performance. In fact, doing things the Rails Way is the #2 best way to run your server into the ground due to useless DB queries (#1 is not using any caching scheme). But hey, you can just tell your customer that they need to pay for a much heftier server, right? *SIGH!*

But, I digress.

[ad name=”banner”]

Anyway, you then had a sessions table with a “userid” column. Rock on. But now you needed to populate that “userid” field with the user’s id number when a new session was created. Thus, you probably did something like this in your login action:

if session[:userid] = User.authenticate(params[:user][:login], params[:user][:password])

session.model.userid = session[:userid]
[...]

Setting up the blank session model magically gave you access to session.model.userid, which would assign the user’s id to the “userid” field in the proper row in the sessions table. Well, this will cause an error in Rails 2.3.2. One new way to do things is like so:

if session[:userid] = User.authenticate(params[:user][:login], params[:user][:password])

Session.update_userid(session[:userid], request.session.session_id)

You may be wondering where the update_userid method comes from. You’re about to create it! In the formerly blank session model file (session.rb), add the following method:

def self.update_userid(id, sess_id)

connection.update("UPDATE sessions SET user_id = '#{id}' WHERE session_id = '#{sess_id}'")

end

Voila! You’re problem is solved.

Note that in Rails 2.3.2, you have to do something with session[:userid] or session[:whatever] in order to make Rails load the session stuff. After that, you can call request.session.session_id in order to use the session id to find the appropriate row in the sessions table for the current user.

So, there you have it – no session plugins or gems required.

On subsequent page hits, you won’t have multiple queries running on the sessions table, since the insanity above only runs when the user logs in. And if you’re really clever, you’ll set up your entire application so that the only database operation being run on most pages is the session query. Cache all the rest of your content, and you don’t need to worry about the relatively minor post-login session DB overhead.

On the other hand, you could always just do things the Rails Way and use the cookie session store…

Need help? Hire me!
Get Scottie Stuff!