Ruby on Rails Migrations

Although migrations are a very cool feature of Ruby on Rails, they are not covered in any of the basic books on RoR i have encountered so far (Agile Web Development with Rails, Ruby for Rails Programmers).

Update: Check out my recent post: Ruby on Rails Migrations: Reloaded for an update.

Both these books are using an ‘in medias res’ style approach – they guide the reader through the essential features of Rails by building a web app from scratch. The models in the examples are creaed in SQL rather than with migrations. Let’s examine the difference on a simple example, taken from AWDwR. (Further I am assuming that you have generated a rails application, a development database for the application and the DB connection settings (database.yaml) are correct.)

The classic way: SQL DDL

Create the sql file, create.sql:

drop table if exists products;
create table products (
id           int            not null auto_increment,
title        varchar(100)   not null,
description  text           not null,
image_url    varchar(200)   not null,
price        decimal(10,2)  not null,
primary key (id)
);

After this, you can create the table with:

mysql name_of_your_DB < create.sql

You are now ready to generate your model.

Doing the same with migrations

In your rails app directory, issue the following command:

ruby script/generate migration ProductMigration

then open the file db/migrate/001_product_migration.rb and edit it. To achieve the same result as in the SQL example, the file should look like this:

class ProductMigration < ActiveRecord::Migration
def self.up create_table :products do |table|
table.column :title,
:string,
:limit => 100,
:null => false

table.column :description,
:text,
:null => false

table.column :image_url,
:string,
:limit => 200,
:null => false

table.column :price,
:float,
:null => false
end
end

def self.down
drop_table :products
end
end

Run the migration wit the following command:

rake migrate [VERSION=version_number]

And you achieved the same result as with the first method!

That's very nice, but...

Well, if the only purpose of migrations would be solely the possibility to write Ruby code instead of SQL, even this would be enough for me to go for them. However, i have to admit that this alone would be a rather feeble argument. The good news is that it is not! There is much more to migrations than writing Ruby code:

  • Migrations are DB agnostic - The 'write once, use everywhere' principle really works here!
  • You don't have to think about obscure SQL specific things anymore - let Rails handle them for you! (OK there are some really complicated things, but fortunately they are adressed by some great books like Rails Recipes, code snippets like Migrate Plus, and I believe that by the Rails team, too.)
  • You can change the database as much as you want, and the data you have already there is not affected.
  • You get very effective versioning: track changes, concurrent versions, upgrade/downgrade your schemas easily!
  • You can generate DB schemas from migrations.
  • And possibly much much more... I am a newbie too! 😉

In my oppinion, judging based on the Rails mailing list discussions, migrations are accepted more and more as the definitve way of creating, maintaining, versioning your DB models - so everybody considering serious Rails development should give them a look!

13 thoughts on “Ruby on Rails Migrations

  1. Your 3rd bullet point isn’t necessarily true. If you use migrations to backout to an earlier version which may entail dropping columns or entire tables, then the data in those columns/tables will disappear too. There isn’t any way to get it back unless you specifically save it off within the migration self#down method.

    Minor nitpick, but I thought it worthy since we don’t want to attribute superpowers to migrations when it isn’t warranted.

  2. Thanks for the comment, cremes!
    I am in the process of learning migrations (and Rails) so i am happy to hear any comments/corrections.

    This blog reflects my observations during learning rails, so it is definitely not an attempt for a  ‘The guru has spoken’ style stuff, but rather an ‘Everything is new to a newborn baby’ style collection of experiences  😉

    I have just bought AWDwR – which uses migrations from the beginning – and also waiting for Rails Recipes paperback, so hopefully i will improve my (migrations) skills significantly in the future…

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

  4. Pingback: Jeff Rasmussen’s Healthcare IT Blog » RoR Migration Tool

  5. Quick question from a newbie – where can I find a list of the the values/ datatypes for all my options when creating tables (i.e. :string, :limit, :datetime). I am sure it is in the api, but just can’t think of the right terminology to look it up under. I actually have the first version of Agile Web 🙁

    Any help would be greatly appreciated – thanks!

    Mike

  6. Well, as for the types, the possible values are:

    Fixnum -> int, integer
    Float -> decimal, numeric, float, double
    Date -> interval, date
    String -> blob, clob, text, char, varchar, string
    Time -> datetime, time

    (On the left side is the Ruby object, on the right the equivalent SQL)

    AFAIK, tha available options are: (cut’n’ paste from the API)

    * :limit: Requests a maximum column length 
       (:string, :text, :binary or :integer columns only)
    * :default: The column’s default value.
       You cannot explicitely set the default value to NULL. 
       Simply leave off this option if you want a NULL default value.
    * :null: Allows or disallows NULL values in the column. 
       This option could have been named :null_allowed.
    

    Hope this helps.

  7. Pingback: 2003 lexus ls430

  8. Pingback: bbw toy

  9. Pingback: tucci

  10. You said that the migration does the same thing as the sql statements. When I use “:float” it doesn’t truncate the decimals to two places like you wanted to in your first example. How do you get migrations to do that?

  11. Occasionally you will make a mistake when writing a migration. If you have already run the migration, then you cannot just edit the migration and run the migration again: Rails thinks it has already run the migration and so will do nothing when you run

Leave a Reply

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