Recent Projects

Configuring Cookie-Based Sessions in Rails 2.0

As of Changeset 6184 and the release of Rails 2.0, the default session store for Rails apps is cookie-based.

[This] means sessions are no longer stored on the file system or in the database, but kept by the client in a hashed form that can’t be forged. This makes it not only a lot faster than traditional session stores, but also makes it zero maintenance. There’s no cron job needed to clear out the sessions and your server won’t crash because you forgot and suddenly had 500K files in tmp/session.

Configuring your application to use this speedy new session store is easy. Adding the following to your config/environment.rb file would do the trick:

config.action_controller.session = {
  :session_key => '_my_app_session',
  :secret      => 'some_really_long_and_hashed_key'
}

But…

I don’t like it.

Especially when you’re dealing with open-source projects, putting what amounts to installation-specific passwords here doesn’t seem appropriate. In the case of my open-source project, El Dorado, I’d like to be able to make changes to environment.rb without troubling the user. Ideally, I think all passwords should be set from a single location. Luckily, it’s easy to push this configuration into the already available config/database.yml.

Here’s how.

Add the following to config/environment.rb:

require 'yaml'
db = YAML.load_file('config/database.yml')
config.action_controller.session = {
  :session_key => db[RAILS_ENV]['session_key'],
  :secret      => db[RAILS_ENV]['secret']
}

And then you can set everything up in one place: config/database.yml:

development:
  adapter: mysql
  database: eldorado_development
  username: root
  password:
  host: localhost
  session_key: eldorado_development
  secret: YrDOFOmYJyFg2tTZykCbZjWYQUbKBt

test:
  adapter: mysql
  database: eldorado_test
  username: root
  password:
  host: localhost
  session_key: eldorado_test
  secret: Pl8qJNFc8mo1yt1xtHOmfUGHOPEutu

production:
  adapter: mysql
  database: eldorado_production
  username: root
  password:
  host: localhost
  session_key: eldorado_production
  secret:

This seems more… natural. Don’t you think?

Anyway, using YAML files for app configuration is the way of the future.

Random Records in Rails

There are a number of different ways to retrieve random items from a database in Rails, most of which have been discussed at length on the Rails wiki. According to this article, there are 3 preferred methods:

  1. Select a Record by Random Offset
  2. Randomize with the Database
  3. Randomize with Ruby

For an in-depth look into these options, you can peruse this discussion page, which details some of the pros and cons of different strategies for randomization.

After trying out a few of the techniques that abound in this area, I stumbled across an article from Jamis Buck, where he discusses a RESTful way to approach the creation of custom finders. Although randomization isn’t the focus of the article, he does provide a bit of guidance in that regard. His strategy uses Ruby for the randomization, and employs 2 light-weight queries. The first query gathers a list of valid ids. The second simply selects a single item using that (randomized) id.

So, I did a bit of cargo-culting and repurposing to achieve an efficient, database agnostic way to retrieve random items from a database using ActiveRecord. Simply add the following to the model from which you’d like to be able to pull random records:

class Widget < ActiveRecord::Base

  # ...

  def self.random
    ids = connection.select_all("SELECT id FROM widgets")
    find(ids[rand(ids.length)]["id"].to_i) unless ids.blank?
  end

end

Then, you can use the following bit of code in a controller like so:

class SomeController < ApplicationController

  # ...

  def some_action
    @widget = Widget.random
  end

end

And you've got a small and efficient "random finder" for use throughout your app. Lovely.

Update I just came across a comment from Rails Core member Koz that provides an alternative that seems compelling at fist glance: