Migrating rails – what it is about?

Summary about this entry:
Basic info about migrations in Ruby on Rails – what it is and how to use it – from novice rails user perspective.

Last few days I was trying to get familiar with migrations in Rails. Now I try to write down what I’m found out. I want to share with other beginners with rails my experiences with migrations, maybe it will be easier to start with Ruby on Rails for someone with this…

I assume You know a bit RoR – at least what it is. If it is not a case go to RoR wiki and Start at the beginning (wiki.rubyonrails.org/rails/pages/StartAtTheBeginning). So lets go things rolling.

I was introduced to Rails via 4 Days on Rails, and there is tip to store Your DB structure in SQL file in rails application directory structure. This allow You to put it under your Favourite Versioning System(TM). But it has some drawbacks. First it is SQL. What is wrong with it? Rails can seamlessly work with many DB engines and using particular DB engine SQL statements makes Your application less flexible, pardon, less agile I should say :)) Other wrong thing in this approach is migration scheme build in rails itself. Living without it is possible, however makes Your application a bit harder to develop in longer time frame.

So what it is migration anyway? Rails has built in system to make changes to databases. It is called migrations and all data needed for rails do migration are stored in db/migration directory. Lets look for an example:

[viciu@bsd60 soccer]$ ls db/migrate/
001_create_teams.rb             003_add_authenticated_table.rb
002_create_settings.rb          004_initial_migration.rb

In my test application there are 4 migrations, number on the beginning of file name is migration version number. As is this test application at the end is initial_migration, but who cares :-)) (a word of explanation – I was playing with migrations and at the end I made migrations 1 to 3 empty and 4th is actually creating my current DB schema). Running migration is as simple as running rake migrate, which runs migrations up to last one as needed. If You need to go to particular state of DB You can run rake migrate VERSION=XXX where XXX is needed migration number (those numbers in migration file names).

And now what are those files? They are plain Ruby code and could look like this:

class InitialMigration < ActiveRecord::Migration      
 def self.up      
  create_table "users", :force => true do |t|
    t.column "login", :string, :limit => 40
    t.column "email", :string, :limit => 100
    t.column "crypted_password", :string, :limit => 40
    t.column "salt", :string, :limit => 40
    t.column "created_at", :datetime
    t.column "updated_at", :datetime
   end
 end

  def self.down
    drop_table :users
  end
end

Basically this file, it is single class, with two methods up and down. Up is called when migrating to higher version of DB scheme, down is called when going to lower DB schema version number. Of course in case of downgrade all data in table users is lost. And we are talking about above example. Going up referrers to changing DB version number to higher one, not about adding something to DB schema. If newer version is a few table columns thinner then in up we will have remove_columns statements and in down add_colums. Simple like that.

Which brings us to question how rails framework knows which version of DB your application currently uses? It knows by checking special table named schema_info. It is created while running first migration, and stores current version number.

But back to our class. Up method looks more interesting. Of course it is table definition written in Ruby code. Nice. It will create table in all supported DB engines, thus is more portable than plain SQL. I did not run on problem with models clash during migrations, but many people more experienced with rails than I recommend to create local model of data, not depending on current application model. What is this about? Lets assume You have in Your application Products table. This mean that better is to define in migration local ActiveRecord class named Product. As I said, I did not run on this issue, but wise people advice to do so ;))

class AddNewColumnToProducts < ActiveRecord:Migration
  class Product < ActiveRecord:Base
  end
  def self.up
    add_column :products, :date_available, :datetime
  end
  def self.down
   remove_column :products, :date_available
  end
end

At strat we create empty Product class, child of ActiveRecord:Base, which covers any current model with its own Product.

When You start with developing application without migration You find yourself (like I did) in DB schema in DB engine, and without any migration. How to create migration with description of current schema? It is very simple. Run ./scripts/generate migration YourMigrationUniqeName. This will create empty migration under db/migration. Next run rake db_schema_dump and this will create db/schema.rb file with current schema definition written in Ruby. Copy and paste into self.up in Your migration, write proper for Your data self.down and ready.

Useful links:
http://wiki.rubyonrails.org/rails/pages/UnderstandingMigrations
http://wiki.rubyonrails.org/rails/pages/UsingMigrations

Leave a comment

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.