Seed Data in Rails

Friday, November 16

Someone asked me about this the other day, so I thought I’d write about it. In some of my applications, I need to “seed” the database with data. This might be a list of categories, sections, or other defaults.

There are a couple of ways you can do this. One way is to use migrations. You create records in your migration via ActiveRecord as you normally would, and when you run your migrations, the data is inserted. This works OK, except it obscures the location of the data. By the time you have a lot of migrations, you’re unlikely to remember that 003_create_categories.rb is also the place where you’re adding your default categories.

I like to think of migrations as being transient. As your schema grows and your project evolves, the chances of your migrations running perfectly from top to bottom diminish. When bootstrapping a database, it’s a much better idea to load the entire schema via db:schema:load than running through each transformation with migrations.

So, if we’re not using migrations for seed data, where do we keep it? I like to use YAML fixtures for this. You could use the test fixtures from test/fixtures, but this is an inappropriate location. If you were a new developer coming on to a project, why would you think to look in the test directory for seed data? Test fixtures are for your tests.

For seed data, I create a fixtures directory inside the existing db/ directory: db/fixtures. Then I use the following Rake task, called db:seed to load them:

namespace :db do
  desc "Load seed fixtures (from db/fixtures) into the current environment's database." 
  task :seed => :environment do
    require 'active_record/fixtures'
    Dir.glob(RAILS_ROOT + '/db/fixtures/*.yml').each do |file|
      Fixtures.create_fixtures('db/fixtures', File.basename(file, '.*'))
    end
  end
end

So, I might have something like db/fixtures/categories.yml. When I’m bootstrapping the project on a new machine (say, when deploying), I’d just do the following:

$ rake db:create:all
$ rake db:schema:load
$ rake db:seed

How are other folks out there dealing with seed data?

Faster Fixtures in Rails 2.0

Monday, October 01

Rails 2.0 includes optimizations for the loading of fixtures in tests that offer a significant speedup. After updating one of my projects to the latest from svn, my tests are running up to 50% faster than before.

Units:
  • before: 17s
  • after: 12s
  • improvement: ~ 30%
Functionals:
  • before: 10s
  • after: 5s
  • improvement: ~ 50%

This particular project has a lot of tests, and to be honest, even 12 seconds is too slow for my tastes. But the improvement sure is welcome. In newer projects, I’m using UnitRecord to test without the database. Obviously, this is much faster. But for fixture-dependent projects, upgrading to Rails 2.0 will yield a significant improvement out of the box.