Tuesday, August 15, 2006

Migrations - A Unique Feature Offered By Rails Framework

How many times has it happened to you that you decided to start your site development or any other e-business that required a database backend and then as the time passed and your business grew, you felt that the database selection was not good enough or the features that are offered by the newer database version or some other database are now a days more powerful and well suited to your business than it was few years back? It happens right!! And it is very natural because the technology changes day after day and so do the database management. You always want to move ahead to acquire better and more powerful functionality and features available.

But when it comes to migrating from one database to another, it’s a real "Pain in the ASS!!" I hope you would agree to that. And no wonder that this pain holds you back from going ahead and upgrading your database to the newer version and thus ultimately compromising with the revenue. And this is more serious a problem for smaller e-business where you cannot afford the cost involved.

Is there a way to get rid of all that pain while migrating from one DB to another according to the requirement change from time to time? The Answer after Rails coming to rescue us is YES!!

Rails has provided an in-built support to the Database Migration. Before showing you how, let us define what Migration is.

What is Migration: It is a feature of Rails framework that allows you to define the changes in the database schema of your web-application using the Ruby Language and thus making it possible for you to migrate from one database to another as well as upgrading or downgrading the database versions. This also allows you to keep a version control system to keep your database changes synchronized with core code.

If we list the Advantages of Migration in Rails, we can have the following points:

  • Help you achieve Database Independency: No matter what database (MySQL, PostgreSQL or SQLite) you switch to at any point in time, once you have your database schema ready in Ruby, you need not change anything further.
  • Cuts the cost of hiring different people having knowledge of the different databases: As the syntax conversion with database change is taken care of internally by the Ruby code.
  • Liberty to choose different databases: Allows you to choose the best database suited for your application by trying different ones easily as you can easily switch between different versions of a database.
  • Facilitates the synchronization of the same database schema in a team of developers working on a single project: As when someone in your team makes a change to the data abase schema, other just need to update, and execute the command rake migrate. And that's done!!
  • Helps you upgrade the database version on the live servers (production servers): While upgrading the database on the production servers you just need to run the command rake migrate. And that's also done!!

If the above discussion makes you think that you should be using the Rails Migration then please go ahead, otherwise just chuck it here itself and wait for the nightmare where you would need to upgrade to a new database!!

Those who realized the impotrence and potential, please come ahead.....

Now that you have realized the impotrence, without wasting a single second let's see how to use Rails Migration in 3 simple steps:

Step 1: Creating Migration using the migration generator: Run the ruby generator, ruby script/generate migration my_migration to create a new migration file. This would create a new file named as versionnumber_migration_file_name.rb in the db/migrations directory of your project. For example, if you want to create a migration file to upgrade the version of the database you are using in which you want to create a new table called entity, then you could run the following command: ruby script/generate migration add_entity_table. A file named as 002_add_entity_table.rb (assuming you already have a migration file, if not the number will be 001 instead of 002) will be created in the db/migrate directory.

Note:

  1. The Migrations has a naming convention and that is that the name of the migrations that you are creating should either contain underscores (my_migration) or they should be camel-cased (MyMigration)
  2. The name of a migration should be unique and should not match with the name of any of the existing models class failing which the rake migrate will fail.

Step 2: Writing the migration code: In the newly created migration file in the db/migrations directory, define "self.up" and "self.down" methods. These methods tell the system what to do when a database version is upgraded to next version or is downgraded to a lower version.

Note: The version that we are talking abouit here is not the version of the database exactly. Instead it is the verdsion of the migration that we are maintaining in the project. The version number here are 001, 002, and so on. This is a means of keeping a version control over the database scema changes thoughout the development of the project.

For example, if you open the newly created file, 002_add_entity_table.rb, you would see the following lines of code in it:

class AddEntityTable <>

def self.up

end
def self.down

end

end


Note that there is no code at all in the self.up and self.down methods. Now our need is to create a new table whenever we upgrade the database version, so we will write the create_table query in the self.up method as follows:

class AddEntityTable <>

def self.up

create_table :entity do ¦e¦

e.column :first_name, :string

e.column :last_name, :string

e.column :joining_date, :date

end
def self.down

endend


Still, you can see that the self.down method doesn't have a body. Now suppose our need is to delete the newly created table (most obvious) while downgrading to the current version again, then we need to write a drop_table query in the self.down method as follows:

class AddEntityTable <>

def self.up

create_table :entity do ¦e¦

e.column :first_name, :string

e.column :last_name, :string

e.column :joining_date, :date

end
def self.down

drop_table :entity

end

end


Step 3: Run the rake migrate command: That's it dude!! You are done with the migration part. Mind blowing!! Right?

You can also downgrade the database version in the similar manner. You simply need to run the rake command again with the version number to which you want to downgrade. For example, if we want to rollback to the older version, say version 1, we will run the following command: rake migrate VERSION=1. This command will run the self.down of the 002 version file and your database will be at the version 1 again.

Note: The rake migrate VERSION=versionnumber, command takes the keyword VERSION all in caps only.

Wondering how rake works? Here is the explanation!!

The command, rake migrate VERSION=versionnumber, automatically decides what to do. What I mean to say is, if you run this command passing a version number lower than the version which you are currently in, then it will run the self.down methods of the all the migration files starting from current migration version file up till versionnumber-1 migration file. On the other hand if you run this command passing a version number higher than the version which you are currently in, then it will run the self.up methods of the all the migration files starting from current migration version up till versionnumber-1 migration file.