Smarter Rails Seeding with Sprig

Lawson Kurtz, Former Senior Developer

Article Category: #Code

Posted on

We love writing Rails apps at Viget. The framework covers so much ground right out of the box by convention. However, Rails is oddly silent about one thing: seed data. Beyond a simple Rake task, db:seed, each project is left on its own to define how best to provide seeds.

Your Seed Data Is Important

Without expounding too much on why seeds are vital over the lifetime of a project, we use them to provide:

  • data that's required for the app to function properly (admin accounts, roles, etc)
  • sample data so staging environments can feel like the real thing
  • data in a variety of potentially intricate states
  • a backdrop for QA testing
  • a reproducible "vanilla" integration server state

Given the many uses across the whole team, we saw a chance to create a standard for our own process. From that effort grew (oh ho!) Sprig.

Introducing Sprig

Sprig

Seed by Convention

Sprig provides common sense conventions for seeding Rails apps. The simplest use might look like:

Step 1:

db/seeds/development/users.yml

 records:
 - sprig_id: 1
 first_name: "John"
 last_name: "Smith"
 date_of_birth: "<%= 1.year.ago %>"

You define your seeds in the formats you love: YML, JSON, and CSV are supported out of the box.

Step 2:

db/seeds/development.rb

 include Sprig::Helpers

sprig User

You tell Sprig which classes should be seeded for the current environment. Sprig finds your lovely seed files and does the rest.

Step 3:

No wait... That's it.

Relational Seeding for Relational Data

All real-world applications contain relationships between models. Sprig allows seeds to reference one another as if they already exist, so seeding relationships is as easy as seeding records.

 records:
 - sprig_id: 1
 user_id: "<%= sprig_record(User, 1).id %>"
 body: "Ipsum lorem"

Keeping track of the order and direction of your seeds' dependencies can be tricky. No worries. Sprig automatically determines the order with which seeds should be persisted. And if you accidently create a circular dependency, Sprig helps you resolve it.

Customization

Although the Sprig convention expects YML, CSV, and JSON seed files, it doesn't limit you to them. You can easily create and use your own custom parser (like this one that lets us use a Google Spreadsheet as our data source). Sprig can be extended to parse any kind of seed file from any source:

 sprig [{
 class: Post,
 source: open('https://spreadsheets.google.com/feeds/list/somerandomtoken/1/public/values?alt=json'),
 parser: Sprig::Data::Parser::GoogleSpreadsheetJson
}]

Sprig also accepts options like find_existing_by which tells Sprig to update records matching provided criteria instead of persisting a new record, allowing for idempotent seeding operations.

Give It A Spin

The full set of features can be found on the Sprig pages. We've already used Sprig on many of our own projects for great justice and hopefully you can too!

So what are you waiting for? gem install sprig

To Improve Is To Change

Something missing? We're actively developing Sprig to be better all the time and are happily accepting issues and pull requests at the project's home on GitHub.


Thanks to Ryan Foster for his significant contributions to this post and the Sprig project, to the entire Viget development team for helping to make Sprig awesome, and to Mindy Wagner for the sweet logo.

Related Articles