Apr 13 2009

Rails Seed Data
8

Seed data in Rails applications has been discussed ad nauseum, but I wanted to throw out another simple option that I use quite regularly. I’ve essentially found that seed data for my applications comes in three different flavors.

1. Always seed

We wipe out and reload this seed data multiple times in a application’s lifetime. A good example of this in SportSpyder is the list of sports such as MLB, NFL, etc. This data is never modified by the application itself, and is essentially read-only. If we want to add a new sport, we can wipe out and reload the seed data for the table without repercussions.

2. Seed once

We seed this data to the table only once. A good example of this is inserting an application’s first Admin user. After seeding the initial data, the application takes over modification and maintenance of the data in that table. You would never want to reseed the table at a later time since this would wipe out additional data added by other means.

3. Development/Dummy data

This is dummy data that we throw into an application to check out how things look before we go live with real content in the application.

Loading the data

Lately I’ve tossed aside test fixtures in favor of using FactoryGirl for testing, but I find yaml files work fine for most seed data (as long as there isn’t too much of it.) You could probably incorporate this idea into object based seeding options as well.

To handle the three different types of seed data, we create a few subdirectories within db/.

mkdir -p db/seed/always
mkdir -p db/seed/develop
mkdir -p db/seed/once

In here we put YML based fixture files with the data we want to load. One thing to remember is that you probably want to manually specify the ids instead of relying on foxy fixtures. You don’t want your id column starting at numbers like 237252458.

We then add a new file named lib/tasks/db.rake with the following tasks:

require 'active_record/fixtures'
 
namespace :db do
  desc "Seed the database with once/ and always/ fixtures."
  task :seed => :environment do 
    load_fixtures "seed/once"
    load_fixtures "seed/always", :always
  end
 
  desc "Seed the database with develop/ fixtures."
  task :develop => :environment do 
    load_fixtures 'seed/develop', :always
  end
 
 
  private
 
  def load_fixtures(dir, always = false)
    Dir.glob(File.join(RAILS_ROOT, 'db', dir, '*.yml')).each do |fixture_file|
      table_name = File.basename(fixture_file, '.yml')
 
      if table_empty?(table_name) || always
        truncate_table(table_name)
        Fixtures.create_fixtures(File.join('db/', dir), table_name)
      end
    end
  end  
 
  def table_empty?(table_name)
    quoted = connection.quote_table_name(table_name)
    connection.select_value("SELECT COUNT(*) FROM #{quoted}").to_i.zero?
  end
 
  def truncate_table(table_name)
    quoted = connection.quote_table_name(table_name)
    connection.execute("DELETE FROM #{quoted}")
  end
 
  def connection
    ActiveRecord::Base.connection
  end
end

And that’s it. You can now seed your data by running:

rake db:seed

And insert development/dummy data with:

rake db:develop

Previous Articles