An Easy Guide To Using Migrations in Rails

Share this article

Migrations in Rails are really awesome. If you haven’t played with them before, migrations allow you to modify the database in atomic steps, making upgrades (and downgrades) much, much, MUCH easier. Every time you run script/generate model [model_name]
, a corresponding migration is created with a unique number — Rails 2.0.x will add an integer that increases, and Rails 2.1+ adds a timestamp.

001_create_model_name.rb # Old style
20081016230401_create_model_name.rb # New style
Of course, migration scripts aren’t new, but where the Rails ones differ is that they are abstracted so there is no SQL involved (unless you want to use SQL that is). The boiler plate code for a migration looks a little like this:

class CreateModelName < ActiveRecord::Migration
  def self.up
    create_table :model_name do |t|
      
      t.timestamps
    end
  end

  def self.down
    drop_table :model_name
  end
end
The two methods, up and down are pretty self explanatory: up gets called when upgrading the database schema, and down gets called when downgrading, and as you can see up
has a create_table method, where down has a corresponding drop_table method. If our model model_name needed a title, an author_id and active flag, our migration would look something like this:

class CreateModelName < ActiveRecord::Migration
  def self.up
    create_table :model_name do |t|
      t.string :title
      t.integer :author_id
      t.boolean :active
      t.timestamps
    end
  end

  def self.down
    drop_table :model_name
  end
end
The beauty of abstracting things away like this is that you don’t need to worry about nuances between databases. For example, a boolean is represented as a small integer when using MySQL, whilst SQLite has a native boolean type. However if you use Rails migrations, you don’t need to worry about this: Rails takes care of it for you. What you might not have realised is that the full Rails environment is loaded when migrations are run, so you can actually run code to perform tasks that would be really difficult (or even impossible) with with just straight SQL. For example, maybe you want to create an extra column that holds a version of a document with all the html tags stripped out. In this case you might end up with a migration that looks like this:

class AddStrippedContent < ActiveRecord::Migration
  def self.up
    add_column :stories, :stripped, :text
    
    Stories.find(:all).each do |s|
      s.stripped = s.content.strip_tags
    end
  end

  def self.down
    remove_column :stories, :stripped
  end
end
I find this feature really useful for setting defaults, such as a default admin user or default categories. Finally, to run a migration, simply type: rake db:migrate and to migrate to a specific version, just add a VERSION environment variable: VERSION=4 rake db:migrate As you can see, this is much easier than having to remember the equivalent commands in SQL!

Frequently Asked Questions (FAQs) about Rails Migrations

What is the purpose of Rails migrations?

Rails migrations are a convenient way to alter your database schema over time in a consistent and easy way. They use a Ruby DSL so that you don’t have to write SQL by hand, allowing your schema and changes to be database independent. You can think of each migration as being a new ‘version’ of the database. A schema starts off with nothing in it, and each migration modifies it to add or remove tables, columns, or entries.

How do I create a new migration?

You can create a new migration by using the rails generate migration command followed by the name of the migration. For example, rails generate migration AddPartNumberToProducts would generate a migration that adds a column called part_number to the products table.

How do I run a migration?

To run migrations, you use the rake db:migrate command. This will run any pending migrations, updating your database schema to the latest version. If you want to run a specific migration, you can use the VERSION environment variable, like so: rake db:migrate VERSION=20180906120000.

How can I undo a migration?

If you need to undo a migration, you can use the rake db:rollback command. This will undo the last migration that was run. If you need to undo a specific migration, you can use the VERSION environment variable, like so: rake db:rollback VERSION=20180906120000.

What is the difference between up and down methods in a migration?

The up method is responsible for applying the effects of the migration, such as adding a new table or a new column. The down method should do the opposite and undo the effects of the up method. This is used when rolling back a migration.

How can I add a column to an existing table?

You can add a column to an existing table by creating a new migration with the add_column method. For example, add_column :products, :part_number, :string would add a string column called part_number to the products table.

How can I remove a column from an existing table?

You can remove a column from an existing table by creating a new migration with the remove_column method. For example, remove_column :products, :part_number would remove the part_number column from the products table.

What is the change method in a migration?

The change method is a more recent addition to Rails migrations. It’s a more convenient way to write migrations where the up and down methods do the exact opposite of each other. If you write a migration using the change method, Rails can automatically figure out how to reverse it when rolling back.

How can I rename a column in a table?

You can rename a column in a table by creating a new migration with the rename_column method. For example, rename_column :products, :part_number, :product_number would rename the part_number column to product_number in the products table.

How can I change the data type of a column?

You can change the data type of a column by creating a new migration with the change_column method. For example, change_column :products, :part_number, :integer would change the data type of the part_number column to integer in the products table.

Myles EftosMyles Eftos
View Author

Myles a Perth-based web developer who has worked in all the major web languages, his weapon of choice being Ruby on Rails—although he’s found himself doing more and more front-end development in JavaScript, HTML, and CSS.

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week