Ruby on Rails: Fixing with Fixtures

This is for proper techies! You were warned!

Introduction
In recent months I’ve had the pleasure of introducing Ruby on Rails to the WWW roster of development environments. It’s been a time of delight, confusion and (oh, so much) frustration but we’re getting to the stage where we are establishing our own best practices and learning from our newbie mistakes. Today I’d like the cover what used to be one of our biggest ROR headaches – migrations and default model data.

Example
Ok, so let’s look at an example. We create a migration to build a simple model, User.

001_create_users
[…]
t.column :first_name, :string
t.column :last_name, :string
[…]

Then we add default users to the model, so that all our developers can work from the same base data.

002_add_users
User.create :first_name => ‘Dan’, :last_name => ‘Nuttall’
[…]

We commit to our repository and everything is rosy. Now we find that the client only needs one naming attribute, name. This means that migration 002 is out of date. For a lone developer, we could perhaps get away with retrospectively changing that migration and raking backwards to zero. But we’re team players here, so we have to add another migration to keep everyone up to date.

003_alter_users
add_column :users, :name, :string
User.find(:all).each do |u|
u.name = u.first_name+’ ‘+u.last_name
u.save
end
remove_column :users, :first_name
remove_column :users, :last_name

Even if we are as careful as possible with our migrations, at all seems very messy and unnecessary. It’s certainly not very DRY. Life doesn’t get any easier when we add validations to the model.

models/user.rb
[…]
validates_presence_of :name
[…]

Now a new developer on the project will get validation errors in the second migration file when trying to migrate from zero. Sure, we could retrospectively alter the first migrations, but then everyone would have to migrate backwards and forwards every time they updated their code from the repository, just in case. And when you’re dealing with a project involving dozens of inter-related models… it’s just too horrible to even consider. Believe me, we tried some pretty horrible techniques to get around this… until we found our salvation.

Enter Fixtures
Fixtures should be familiar to everyone who deals with testing in Rails (and we all test, right?). Fixtures allow us to build up test data for models in a YAML format. So we would create our test user instances like this:

fixtures/users.yml
first:
id: 1
name: Daniel Nuttall

These get loaded into a temporary database before our tests are run. However, we can load these elements directly in our development database, using the rake command rake db:fixtures:load. You can even specify selected fixtures to add to your dev database using the FIXTURES parameter. This allows us to completely separate our base data from the model construction. We can reload and change these fixtures whenever we alter the underlying models without any fear of breakage.
This has the double advantage that our Unit and Functional tests ensure that our fixtures are current and up-to-date, so we never get caught out with inaccurate data.
So here’s our first Rails Rule: Leave the architecture to the migrations and the data to the fixtures.

What are your rules?

Share this article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • NewsVine
  • Slashdot
  • StumbleUpon
  • Technorati

0 Responses to “Ruby on Rails: Fixing with Fixtures”


  1. No Comments

Leave a Reply