Skip to content

Instantly share code, notes, and snippets.

@mahemoff
Last active May 18, 2017 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mahemoff/3ff04cf2c076578c7da3fe6bb9c3671f to your computer and use it in GitHub Desktop.
Save mahemoff/3ff04cf2c076578c7da3fe6bb9c3671f to your computer and use it in GitHub Desktop.
Rails seeding framework

RATIONALE

It's important to have useful test data during development and debugging, resembling real-world data. It can be cumbersome to setup and maintain though. This is a mini-framework to help with seeding in Rails using a Domain Specific Language approach.

DESIGN APPROACH

  • I got tired of maintaining seeds.rb idempotently. Too dangerous to run this directly into production and overall, cumbersome to make it idempotent (ie work whether or not the objects already exist). So I decided to just make something that's just used for development, starting from an empty DB each time. I'm now maintaining a separate folder of individual data migrations to be performed in production. There's also separate fixtures for testing (separate data than this for performance reasons, and because tests need different kinds of data).
  • It's modular enough for parts to be invoked during testing.
  • The modularity is also part of a domain-specific language approach to seeding, as can be seen in the examples.

USAGE

Just include the files as above. This is a quick rough cut, you'll need to fill in more details.

# db/seeds/model_makers.rb
# A mixin with simple factory methods to generate objects.
# A little like Factory Girl.
module ModelMakers
def user(name, attribs={})
User.create attribs.merge(name: name)
end
def stories(author, text, attribs={})
author = Author.get(author) # general-purpose retriever (can support IDs, objects etc as args)
Story.create attribs.merge(author: author, text: text)
end
end
# db/seeds/seeders.rb
class Seeders
include ModelMakers
include Singleton
### FRAMEWORK
def self.seeder(name, &block)
Seeders.seeders ||= []
Seeders.seeders << name
define_method("seed_#{name}", &block)
end
def run_all
the_seeders = Seeders.seeders
the_seeders.each { |seeder|
puts "Seeding: #{seeder}"
self.send "seed_#{seeder}"
}
end
### EXAMPLES OF SETTING UP THE UNIVERSE
seeder "users" do
user 'Jane'
user 'Tito'
end
seeder 'stories' do
story 'Jane', 'Doctors hate this medieval remedy'
story 'Tito', 'This tardigrade wants to run for office'
end
end
# db/seeds.rb
if !Rails.env.in? %w(development test)
puts 'run this only in dev/test'
exit 1
end
DatabaseCleaner.clean_with :truncation, reset_ids: true
Seeders.instance.run_all
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment