Conditionally Disabling Database Sessions in Ruby on Rails 3

I’ll start with the obvious: Why would you want to conditionally disable database sessions in Ruby on Rails 3? It’s a problem I’ve faced with BugMuncher for a long time, but for a different reason than most. The most common reason people want this is to stop sessions being created for web crawlers (bots). Here’s a couple of people having this issue - this person and this one too.

The first link covers disabling Cookie based sessions for bots, but for those using Database storage it doesn’t work.


Not interested in the how or why? Simply create a file config/initializers/session_store_ext.rb and fill it with the following. Also make sure to define BOT_REGEX to match known crawler user agents.

# Save this file as config/initializers/session_store_ext.rb 
# and don't forget to define BOT_REGEX

class ActiveRecord::SessionStore
  _set_session = instance_method :set_session

  define_method :set_session  do | env, sid, session_data, options |
    unless env['HTTP_USER_AGENT'] =~ BOT_REGEX
      _set_session.bind(self).call env, sid, session_data, options


  private :set_session

The gory details

As I mentioned earlier, the issue with BugMuncher wasn’t crawlers, as the BugMuncher app disallows crawlers through its robots.txt, and even if it didn’t, the bots would only ever see a login page.

The issue I was having with BugMuncher was actually much worse - The BugMuncher feedback tab is embedded in hundreds of sites, and any time someone saw the BugMuncher feedback tool on any website, a completely unneeded session was created in BugMuncher’s database. Even with a script to clean out old sessions, there were millions of rows in the sessions table, and it was steadily growing. Something had to be done.

After a couple of hours of Googling, and only finding solutions that covered cookie storage, I realised I’d have to fix this one myself.

Finding the session storage code

I spent some time digging through the Rails source code, but at this point I wasn’t too sure what I was looking for, so I decided to take a more direct approach: On my local machine I deleted the sessions table and fired up my local copy of BugMuncher, knowing it would throw an error when it couldn’t find the sessions table. This gave me a stack trace which I hoped would guide me to the file I needed to modify.

One line in the stack trace instantly stood out:

activerecord (3.2.8) lib/active_record/session_store.rb:307:in `get_session'

The get_session method was probably not going to be exactly what I was looking for, as the loading of sessions wasn’t the problem, I needed to find where they were saved. It was very close though, as a set_session method is defined directly below get_session, and that was the method I needed to overwrite.

BugMuncher uses a slightly different monkey patch to the one above, as I needed to disable sessions based on the current controller, instead of the user agent. This is only a slight (1 line) difference, and both patches do the following:

  1. Store the original set_session method as _set_session, so that it can still be called (you can’t use super when monkey patching).
  2. Define a new set_session method.
  3. In the new set_session method check to see if the request is from a bot (or in BugMuncher’s case, a specific controller).
  4. If so, just return the Session ID (what the original method returns) without saving the session.
  5. Otherwise bind the currently unbound original _set_session method to the current object, call it, and return the Session ID
  6. Make the new set_session method private, this isn’t required, but the original set_session method is private, and I like to respect that.

That’s the story of my first Rails Monkey Patch, and one that has since slowed down the growth of BugMuncher’s sessions table by a factor of around 14,000


Every time I write ‘Conditionally Disabling Database Sessions in Ruby on Rails 3’ I can’t help but think of this:

Tube Man

- Matt Bearman