Ruby on Rails Migrations Reloaded

In my previous post on migrations i wrote that “…they are not covered in any of the basic books on RoR”. Well, this statement does not hold anymore, since Agile Web Development with Rails, 2nd ed. is already creating the models with migrations.

While the last part of the post (why are migrations so cool) is still up-to-date, they way of creating migrations is different from 1.1 on, so i have decided to review the topic and add some new points, too.

Migrations are now created automatically with the model

In my previous post, i have been creating the migration manually with the command

ruby script/generate migration ProductMigration

However, as of Rails 1.1, you don’t have to do this anymore. When you generate the model (let’s stick with the Product model as an example) the migration is automatically generated:

ruby script/generate model Product
...
... #some lines omited
...
create db/migrate/001_create_products.rb

Now you can edit the file db/migrate/001_create_products.rb to contain something like this:

class ProductMigration < ActiveRecord::Migration
def self.up
create_table :products do |table|
table.column :title,       :string
table.column :description, :text
table.column :image_url,   :string end
(rest of the file omited)

Then run

rake db:migrate

To update the database. That's even easier than in the previous versions of rails!

Valid column data types and possible options

Valid columns are:

integer, float, datetime, date, timestamp, time, text, string, binary and boolean.

Valid column options:

  • limit ( :limit => “50” )
  • default (:default => “blah” )
  • null (:null => false implies NOT NULL)

string is the equivalent of varchar(255), so if you would like to have a string column (called title) of length 100 instead of 255, with default value 'Some title' and to forbid NULL value, you have to type

table.column :title,
:string,
:limit   => 100,
:default => "Some title",
:null    => false

Generating test data

I am quite sure you know the situation when you want to test something quickly and you waste precious time to generate some test data, which you trash after the testing just to find yourself in the same situation later?

Well, migrations can help you to prevent headaches because of this, too. Here is how:

ruby script/generate migration create_test_data
Create db/migrate/002_create_test_data.rb

You can create test data inside the migration file like this:

class ProductMigration < ActiveRecord::Migration
def self.up
Product.create(:title => 'My cool book about the meaning of life',
:description => '42',
:image_url => /images/cool_book42.png)

You can now commit this migration to the RCS you are using, and modify/add more test data later.

The other advantage is that your colleagues won't spend time writing dummy test data either: they can just check out this migration and happily use the provided tests.

If this is still not enough for you...

You can write SQL statements inside the migrations. For example:

execute "alter table items
add constraint fk_items_products
foreign key (product_id) references products(id)"

However, use this with care since you have to write native DDL statements, which violates one of the fundamental 'cool factors' of migrations: independence from DB vendors.

Conclusion

The Agile Web Development with Rails, 2nd ed can be considered as the Rails bible and since it is promoting migrations as the definitive way to handle your DB issues, i think migrations will become (in fact the already did for lots of people) the state of the art. After using them for a while and enjoying the power and flexibility they provide without having significant drawbacks, i don't really see why should one not use them in the future.

5 thoughts on “Ruby on Rails Migrations Reloaded

  1. Pingback: Ruby, Rails, Web2.0 » Blog Archive » Ruby on Rails Migrations

  2. Pingback: Like Your Work » Blog Archive » links for 2006-08-05

  3. using migration, how do I change a column type. For example, I did this: add_column :products, :price, :decimal. Now I want decimal to be of type float.

Leave a Reply

Your email address will not be published. Required fields are marked *