Geeks With Blogs
Aaron Feng Agile Software Development (XP), Test Driven Development, .NET, etc.....

Recently I decided to check out the beta version of Agile Web Development with Rails book, which is targeted to be released this fall.  It is very interesting that the authors also brought agility into book writing.  It allows readers to provide feedback to new material during the development of the book.  I am also glad to see that the migration part of the framework has become a big part of the book, even having a separate chapter dedicated to it.  It uses migration instead of DDL in the entire demo application.  Besides the migration, there are many significant updates to various parts of the book. But in this post, I will focus mostly on the migration tool.

The migration tool is targeting Rails applications, but it can also be useful outside the Rails world.  There are some people out there already (includes us, here is my old post on it) experimenting using Rails migration as "Enterprise glue" to maintain database schemas.  I hope the final release version of the book will have something on this topic.

I will outline the basics of rails migration below for those are not familiar with it.

What is Ruby on Rails Migration?

At the most simple level, it allows developers to change the database schema as the application requires it in a simple and easy manner.  Instead of writing DDL scripts, you use Ruby as a DSL (domain specific language) to describe what the schema should look like when the changes are required.

Why use it?

The migration tool allows developers to upgrade or downgrade a schema version without loosing data (of course, if you drop stuff it will be lost).  Sure, you can write DDL that does the same thing for you (sort of, but not really without some external tooling), but it will take a lot more effort especially when you are supporting more than one database.  In theory, the migration script you write for one database should work on other databases as long as the operation is supported (currently, it supports all major databases including open source alternatives).  I said in theory because not all databases behave exactly the same way for a given operation. There might be some minor differences, but that's for another post.  If you need to extend or change the existing migration functionality, it is usually very easy to do so.

How does it work?

You basically write a Ruby class that inherits from ActiveRecord::Migration to describe what needs to be accomplished.  There are only two methods you need to write, up and down.  Up method will be called during an upgrade, and down method for downgrading.

class AddTable < ActiveRecord::Migration
  def self.up
    create_table :cars do |t|
      t.column :model,       :string
      t.column :year,          :int
      t.column :make,        :string
      t.column :comments, :text
  def self.down
    drop_table :cars

In this trivial example, it creates a cars table with model, year, make, and comments columns.  One interesting thing to note about model and make columns are both string type.  This is not DDL we are working with.  Migration uses Ruby classes to encapsulate the internal database types in order to abstract out the databases.  Depending on what type of database you are using, string type might vary, but it tends to be pretty consistant across different databases.  In the down method, it just does exactly the opposite, as if the script has never been run.

On the command line, if you run “rake db:migrate”, your database will be upgraded to the latest version.  In this case, the cars table will be added.  Each migration script will have a 3 digit number in the start of the file name which represents the schema version of the script.  That same version number is also stored in the database you are using.  That is how migration knows which script to run during an upgrade or downgrade.  Using the example above, the file name would look something like the following:


Lets say you are currently on version four but you need to roll back to version one, you can run the following command:

rake db:migration VERSION=1

Migration supports most of the operations you would need to perform on the daily basis.  But if you need to do something it does not support you can always execute DDL in your migration script.

One of the really cool things about using Ruby as a DSL is that you have the power of a real programming language to create your migration scripts. This comes in really handy when you need to create test data.

I only scratched the surface on the stuff I covered on Rails migration.  I would encourage anyone that is interested to read the Rails book.

Posted on Saturday, September 30, 2006 8:30 PM Ruby | Back to top

Comments on this post: Ruby on Rails Migration

# re: Ruby on Rails Migration
Requesting Gravatar...
I'm reading the rails boook, page 94 demonstrates how to have rails create test data via a migration. . . and it doesn't work. So far rails has proven to be a rather undocumented mess of crap with a community largely unwilling to help.

Yeah, I guess I trolled...but this rails thing is pissing me off.
Left by anon on Nov 05, 2006 2:55 AM

# re: Ruby on Rails Migration
Requesting Gravatar...
I would have to say, I comletely disagree with your blanket statement. Creating test data should be fairly trivial. What kind of problem are you having?
Left by Aaron Feng on Nov 06, 2006 9:20 PM

# re: Ruby on Rails Migration
Requesting Gravatar...
It has definitely hurt get the rails environment running it seems most people are willing to write apps for themselves on their makes. However, redhat wrote a good article that only missed one piece of the puzzle (database.yml setup).

Getting RoR running on a production web server running apache took me nearly 20 hours over a week to complete.
Left by Thomas Branch on Feb 07, 2007 10:41 AM

# re: Ruby on Rails Migration
Requesting Gravatar...
The current version of "Agile Web Development with Rails", second edition, does cover creating data via a migration. It is in section 16.4, page 275 and following in the PDF version. An example for creating an initial administrator user for their store would be:

# added in a def self.up
salt = "NaCl"
admin = User.create(
:name =>"admin",
:hashed_password => User.encrypted_password("secret", salt),
:salt => salt)!
Left by JG Heithcock on Mar 27, 2007 8:55 PM

# re: Ruby on Rails Migration
Requesting Gravatar...
I can't seem to get rollback working for me, and I'm wondering if it's a simple syntax error. However, I'm pretty certain that the syntax for migration is:

rake db:migrate


rake db:migration

as you have it in your article.
Left by anon on Oct 07, 2007 5:12 AM

# re: Ruby on Rails Migration
Requesting Gravatar...
if your data import via migration didn't work, try using the create! method instead of the create method and it will report any exceptions.

for example, if you were validating a field in the model (eg. validates_presence_of) and the validation failed (eg. the field was empty in your data), your data would not be imported and you wouldn't receive any indication that it failed.
Left by j on Oct 20, 2007 3:28 AM

# re: Ruby on Rails Migration
Requesting Gravatar...
There is a really useful compact Rails Migrations cheatsheet in printable PDF format for download here: Migrations cheatsheet
Left by David on Nov 30, 2007 3:23 PM

# re: Ruby on Rails Migration
Requesting Gravatar...
It's indeed a typo:

rake db:migrate instead of rake db:migration

You may also need to apply the timestamp in the version instead of an integer.

For example VERSION=20090509091831 instead of VERSION=1. You can find the exact timestamp both in the filename of the migration file or by looking directly in the DB, in the table called schema_migrations
Left by Rouk on May 09, 2009 5:18 AM

Your comment:
 (will show your gravatar)

Copyright © Aaron Feng | Powered by: