Rails provides functionality called “migrations.” Migrations allow you to write database-level code in a platform-independent way. For example, if you’re creating a blog, and you have a Post model, the following migration would create the Posts table:
class CreatePostsMigration
def self.up
self.down
create_table :posts do |t|
t.string :title, :post_slug
t.text :body
t.timestamps
end
end
def self.down
drop_table :posts
end
end
The up method executes when the migration is run, and creates the table; the down method executes when you undo the migration.
You can see the table declaration–each of the columns, and their types–something closer to Rails types than database-specific types–is listed. t.timestamps creates the created_at`and updated_at columns, which Rails automatically populates.
You can also create data in a migration–say you want to populate some basic data, like a list of countries. You can create a migration like this:
def self.up
down
Country.create(:name => "Algeria", :code => "AG")
Country.create(:name => "Canada", :code => "CA")
#... add more ...
end
def self.down
Country.delete_all
end
end
Notice how the migration is working–it’s creating objects, not inserting rows–because Rails handles the object-relational mapping.
Additionally, migrations create an easy way to apply changes to a database of a production application. Observe the following migration, which renames the post_slug attribute of the Posts table to url, and adds a views column:
class RenamePostSlugAndAddViewsMigration
def self.up
add_column "Posts", :views, :integer
rename_column("Posts", "post_slug", "url")
end
end
And that’s a brief but comprehensive tour of migrations. The most important part is knowing HOW to run migrations.
To update your database to use all the existing migrations, type: rake db:migrate. Rails will check what version of migrations your application has run, and run only the new migrations. To revert to a previous version of migrations, simply run rake db:migrate version=x. (To reset all migrations, use version=0.)
Each migration sits in a separate class in a separate file. The important thing to note is the number prefixing the filename–that number is what Rails uses to determine what migrations need to run. When you say rake db:migrate version=7, Rails looks at the current version–say it’s 4–and runs all the necessary migrations (in this case, 5-7). If the current version is 10 and the target version is 7, Rails will revert migrations 8-10 (by calling the down methods).
And that’s migrations–an easy way to:
- Abstract database code from the underlying database vendor
- Populate data at an object level, rather than a table-level
- Modify tables in production databases
- Revert the the database schema to a previous version
And you can even add indicies and other constraints through a migration. For more details, see the migration API or the Migrations Cheat Sheet.