13 March 2008

Seed Data for Your Rails 2 Apps - Another Approach

Historically, I've used migrations to set up standard data that my database must contain in a Rails app. This would be things like standard Roles for the system, or maybe country codes or such things. However, it appears this simply won't work in Rails 2.x, because as far as I can tell, when you run something like "rake test", it blows away ALL data in your database (not just fixture data). If I'm wrong about that, please correct me. This makes sense given that it seems the drive is towards schema.rb being the official way to create a DB from scratch, and that you have the equivalent of Foxy fixtures which do lots of magic to make creating your fixtures easy (but likely quite painful to figure out how to explicitly clean up those fixtures in certain cases - so it's easier just to wipe the DB clean).

There are various solutions for creating seed/standard/structured data for your app. However, from what I've seen none address this problem that that data will get wiped out when testing. For many people that may not matter, their tests may not hinge on it. But, I like to stay DRY, and when you have standard roles, or similar types of data, there is no reason I should have to recreate those in fixtures (and risk being out of sync), or leave them out, etc. I likely have app functionality that directly depends on such things, and thus I need this during testing as well.

My solution as of now is a simple one, and one that does not scale well for large amounts of data, but for the five records I need at this point in the particular app I'm working on, it's an approach (I very much welcome better approaches!)... I simply created a "seed_data.rb" file in my config/initializers directory. Within this file I have code that does a create_or_update (or similar) of the standard data I need. This seems to work out quite well.

Update: the above breaks things like "rake db:reset", because when the initializers run, as part of the Rake environment, and the DB has been dropped, the initializer fails, and thus fails rake.


Brennan Dunn said...

I know a lot of this seed data discussion is going to be moot with Rails 3, but when using your initializer method, I found the best way to handle db:migrate:reset and the like was to wrap the initializer seed logic with:

unless Rails.env.test? || ENV['_'] =~ /rake/