summon

Provides a nice DSL for creating dummy data using Factory Girl factory definitions.

Why

Now that you’ve moved away from fixtures (well, you have, haven’t you?) and started using factory_girl in your tests and specs, it would be nice to have a succinct way to generate dummy data for use in development.

In the past I’ve just used a bunch of extra factories for this, but it’s a lot nicer to be able to build an arbitrary number of objects, each with its own set of associations.

Example

Here is an example Rakefile from a project I’m working on:

namespace :summon do
  desc "Builds a ton of dummy data"
  task :build => ['environment', 'db:reset'] do

    require 'spec/support/factories' # load factory definitions
    require 'summon'

    published_date = lambda {
      method = %w(ago since)[rand(2)]
      rand(100).days.send(method)
    }

    Summon(:label, 5)
    Summon(:blog_topic, 10)

    Summon(:user, 20) do |user|
      user.blogs(3..8,
        :topic => BlogTopic.all,
        :published_at => published_date
      ) do |blog|
        blog.comments 0..4
      end
    end

    Summon(:artist, 20) do |artist|
      artist.events 4..6
      artist.releases(0..5,
       :label => Label.all
      ) do |release|
       release.tracks 8..12
      end
    end

    puts "Your minions are ready!"

  end
end

Installation

I’d go for the gem.

sudo gem install jim-summon

Usage

Specifying how many objects to build

You can use an integer or range when specifying how many objects to build:

Summon(:monkey, 3)         # build 3 monkeys
Summon(:monkey, 3..6)      # build between 3 and 6 monkeys

Object attributes

Other attributes to set on created objects (potentially overriding those defined by the factory) are passed in as a hash:

Summon(:monkey, 42, :dangerous => true)     # builds 42 dangerous monkeys

If you pass a proc in as an attribute, it will be evaluated for each object and the resulting value used in its place.

If you pass an Array in as a value to an attribute, a value from the array will be selected at random. This might seem odd, but I’ve found it’s much more common to want to set an attribute or association randomly from a set of options than set an attribute value to be an array. You can always use a proc for this.

Associated objects

This is where the magic really happens. Use a block to define an object’s associations, and potentially their attributes:

Summon(:car, 4) do |car|    # Build 4 cars, and in each...
  car.passengers 3          # Build 3 passengers
  car.driver                # Build one driver
end

Right now has_many and has_one associations are supported. has_many :through is not. Associations can be nested as deep as you like:

Summon(:car, 4, :color => 'red') do |car|
  car.passengers 3, :backseat_driver => true
  car.driver do |driver|
    driver.gloves 2             
    driver.jacket do |jacket|
      jacket.pockets 2, :cents => [0,5,10,25,50]
    end
  end
end

Note on Patches/Pull Requests

  • Fork the project.

  • Make your feature addition or bug fix.

  • Add tests for it. This is important so I don’t break it in a future version unintentionally.

  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but

    bump version in a commit by itself I can ignore when I pull)
    
  • Send me a pull request. Bonus points for topic branches.

Copyright © 2009 Jim Benton. See LICENSE for details.