Rails: Seed Data

Seed data is the setup data that we put in our database, for example we create a few initial user accounts for our application administrators.

This page explains how we create seed data.

Seed Data in YAML files

We use the Rails convention of putting our seed data files here:

  /db/seeds/

We create a YAML file for our seed users:

  /db/seeds/users.yml

The users YAML file defines each user's fields like this:

  alice:
    name: "Alice Adams"
    mail: "alice@example.com"
  bob:
    name: "Bob Brown"
    mail: "bob@example.com"
  carol:
    name: "Carol Cox"
    mail: "carol@example.com"

Rake task to load seed data

We use the Rails convention of putting rake tasks here:
  /lib/tasks/
We use a rake file for our seeds:
  /lib/tasks/db_seed_users.rake
The task provides the rake namespace, runs any setup tasks, then calls a normal ruby method:
  # rake db:seed:users
  namespace :db do
    namespace :seed do
      namespace :users do
        task :default => %w(environment) do
          db_seed_users
        end
      end
    end
  end
The normal ruby method loads the YAML file and iterates on each user:
 
  # Seed multiple users by loading the YAML file
  def db_seed_users
    path=Rails.root.join('db','seeds','users.yml')
    puts "Seeding file #{path}"
    File.open(path) do |file|
      YAML.load_documents(file) do |doc|
        doc.keys.sort.each{|key|
          puts "Seeding key #{key}"
          attributes = doc[key]
          db_seed_user(attributes)
        }
      }
    end
  end

  # Seed one user
  def db_seed_user(attributes)
    # Do any user specific setup here...
    User.create(attributes)
  end
To run the rake task:
  rake db:seed:users

How to make seeds run more than once

We want to be able to run our seed task more than once and still get produce same set of users.

To do this, we add code that checks to see if the user already exists, and if so, skips creating that user:

  # Seed one user
  def db_seed_user(attributes)
    mail = attributes['mail']
    user = User.find_by_mail(mai)
    if user
      puts "This email address exists: #{mail}"
    else
      puts "This email address is new: #{mail}"
      User.create(attributes)
    end
  end

How to create teams

We create teams the same way. We use a YAML file for our seed teams:
  /db/seeds/teams.yml
The teams YAML file defines each team's fields like this:
  red:
    name: "Red Team"
  green:
    name: "Green Team"
  blue:
    name: "Blue Team"
We create a similar rake file:
  /lib/tasks/db_seed_teams.rake
We create a similar inner method:
  # Seed one team
  def db_seed_team(attributes)
    Team.create(attributes)
  end
To run the rake task:
  rake db:seed:teams

How to associate users and teams

We want each team to have a team lead, which is the user who is responsible for the team.
  class Team < ActiveRecord::Base
    has_one :lead, :class => user
    ...
  end
We add a lookup field to the team YAML file:
  red:
    name: "Red Team"
    lead: "alice@example.com"
  green:
    name: "Green Team"
    lead: "bob@example.com"
  blue:
    name: "Blue Team"
    lead: "carol@example.com"
We add code to the inner method to look up the lead user:
  # Seed one team
  def db_seed_team(attributes)
    attributes['lead'] = User.find_by_mail(attributes['lead'])
    Team.create(attributes)
  end



What's Next?

blog comments powered by Disqus