Migrations in Ruby on Rails allow us to make changes in the database schema in a convenient manner. Rails migrations help keep track of what new changes are made to an application’s database schema, when each change is made, and the order in which the changes are made.
Migrations provide lot of benefits, including:
When working on a large project with different team members, it gets easier to keep track of all the changes that the schema goes through.
Migrations make it easier to rollback to an older schema version, undoing specific migrations.
Rails migrations make changes more readable and easier to understand.
Each developer will know whenever a schema is updated, and they can use migrations to speed up to the latest version.
Each migration is stored as a separate file in the project’s db/migrate
folder. Each migration file consists of a single Ruby class with a certain syntax that makes it easy to understand what new changes are being incorporated to the schema.
Since Ruby on Rails is a convention over configuration framework, the migration setup follows a well-defined path.
Each new migration file is titled in the format
YYYYMMDDHHMMSS_create_products.rb
.
For instance, if we are generating a migration file from a class named CreateProducts
on at time , the file name would be 20080906120001_create_products.rb
.
The first part of each migration file’s title is a timestamp that tells us when the migration file was generated. This is helpful because it lays out a chronological timeline of changes to the schema.
Rails automatically creates a timestamp whenever a user creates a migration file. The second part of migration file’s title depicts what the purpose of the migration is. This is also inferred by rails based on the command the user entered into the terminal to generate that file.
We can create a migration file using the following command:
rails g migration AddPriceToProduct type:string
The AddPriceToProduct
statement in the command will tell Rails that the migration is meant to add a new column to the products
table. If we entered a command that began with Create
or Remove
instead of Add
, Rails would identify that those migrations were meant to either create a table or remove a column from a table. Therefore, we need to follow a particular convention when entering a command to generate a migration.
The term
g
in the command shown above is a short alternative forgenerate
. These two terms can be used interchangeably. Therefore, the command,rails generate migration AddPriceToProduct type:string
would also produce the same result.
The command above will create a file similar to the one shown below:
class AddPriceToProduct < ActiveRecord::Migrationdef changeadd_column :products, :price, :floatendend
The migration file will consist of a Ruby class whose name is derived from the command entered to generate migration. Rails not only obtains the class name, but also deciphers what type of migration the user intended to create. As a result, the class is already populated with the relevant code used to add a new column to the the products
table. It also infers that the new column will store data of type float.
Similarly, if we entered the command given below, Rails would infer that the user intends to remove a column but, instead of the add_column
keyword, it will use the remove_column
keyword.
rails generate migration RemovePriceFromProducts price:float
The command will proceed to generate a migration file as shown below:
class RemovePriceFromProduct < ActiveRecord::Migrationdef changeremove_column :products, :price, :floatendend
The Active Record in Rails keeps track of which migrations have been executed. Once you are done creating a migration file, you only need to enter the following command:
rails db:migrate
This command will execute all the migration files that have not yet been executed. Active Record also keeps track of which migrations are still pending. With the execution of each migration file, the
You can create migrations to add, remove, and update columns, and also create or drop tables. You can also rollback migrations that have already been executed. Rails provides a very versatile functionality to manage and update the project’s schema using migrations.
In case a migration has been executed and is now a part of the application’s database schema, it can always be rolled back or reverted to a state prior to when that particular migration altered the schema.
rails db:rollback STEP=1
The command shown above will undo the most recently executed migration. The STEP=1
portion of the command makes sure that only the most recent migration needs to be rolled back. In case we want more than one migration to be rolled back, we can change the number of the STEP
flag.
For example, STEP=3
would roll back the three most recent executed migrations.
A limitation of this command is that no out-of-order migration file can be rolled back, and only migrations that occurred in a sequence can be handled (we get to specify up to what point using the STEP
flag).
In case an out-of-order migration has to be reverted, which would mean no migration before or after it would be affected, we can use the following command:
rails db:migrate:down VERSION=20100905201547
The VERSION
flag is used as an identifier for the migration that needs to be rolled back. The number, which is always the first part of the title of each migration file, represents the timestamp of the migration.
A simple rails application is shown below. You can use this application to test out the commands discussed in this shot. Follow the given guidelines to interact with the application:
product
objects using the create product form.Ctrl + c
to stop the application and use the terminal yourself.rails db:rollback STEP=1
rails s -b 'ssl://0.0.0.0:3000?key=localhost.key&cert=localhost.crt'
If everything worked fine, the price column in the UI should disappear. This is because an if condition has been added to the page that only shows the price column at the frontend if the Product
model contains a price
column.
Please note you should be in the
/myapp/test_proj
directory in the terminal for the commands to work.
And that’s it! You can try adding in different commands in the widget given below as well.
//= link_tree ../images //= link_directory ../javascripts .js //= link_directory ../stylesheets .css