Get a better understanding of Rails Migration

Tram Ho

I. Overview

Hi everyone, as a Rails developer you are no stranger to the concept of migration.

Migration in Rails allows us to develop database (database) throughout the life of an application. Migration allows us to write simple Ruby code to change the state of the database by providing elegant DSL. We don’t need to write database-specific SQL because migration provides abstractions to manipulate the database and take care of the details … when converting DSL into database-specific SQL queries. Migration also provides ways to execute raw SQL on the database, if required.

When creating an application with Rails it always generates a directory called db/migrate , which contains all the migrations we will create.

For starters, we will create a rails app:

Next, we will migrate a user table with the column: name into the database.

The above command will create a file in the db/migrate directory that contains the timestamp as follows: 20200521135455_create_users.rb .

Let’s find out what this migration file looks like:

1. Timestamp in the file name:

  • Every migration file created by Rails will have the timestamp in the file name.
  • This timeline is very important and is used by Rails to confirm when a migration is running or not. I will go into more detail in this section later.

2. Rails version appears in superclass

  • Migration contains a class that inherits from ActiveRecord::Migration[6.0] . As I am using Rails 6, the superclass migration contains [6.0] . If you use rails 5.2, the superclass will be ActiveRecord::Migration[5.2] . We will discuss why the Rails version is part of the superclass name below.

3. change method

  • Migration has a change method that contains DSL code that manipulates the database. In the example above, the change method creates a users table with a string name column.

4. t.timestamps

  • Migration uses the code t.timestamps to add created_at and updated_at timelines to the database table.

When we run the migration using the rails db:migrate command, it creates a users table with the column name with type type as string and column created_at , updated_at with type as datetime .

The actual database column type will be either varchar or text , depending on the database.

II. Detail

1. Importance of timestamps and schema_migration table.

1.1. timestamps

Every time a migration is generated by the rails g migration command, Rails will generate the migration file with a unique timestamp. Timestamp in the form of YYYYMMDDHHMMSS . When a migration runs, Rails inserts migration timestamp into schema_migrations table. This table was created by Rails when we first ran migraion. This table contains only the version column, which is also the primary key. This is the architecture of the schema_migrations table.

Now that we run the migration to create the users table, look below, if Rails contains the timestamp of this migration in the schema_migrations table.

If we re-run migrations. Rails will check to see if that timestamp already exists in the schema_migrations table, if it exists then it will not be executed. This ensures that we can increase the database changes over time and the migration will only run once on the database.

1.2. schema migration

When we run migrations many times. Database schema will continue to be expanded. Rails stores the latest database schema in the file db/schema.db . This file represents all migrations that run on the database throughout the application life cycle.

Because of this file, we do not need to keep old migrations files in codebase. Rails provides the task to dump final schema from database into schema.rb and load schema into database from schema.rb . Therefore, older migrations can be safely removed from codebase. Loading schema into the database is also faster than running each migration every time we set up the application.

As we mentioned the verson of rails in the migation file, let me find out why.

2. Rails version in the migration file

Every migration we create has a version of Rails as part of a superclass. So if our application is using Rails 6, then of course our migration file will have the form ActiveRecord::Migration[6.0] , if the application uses Rails 5.2 then it will take the form ActiveRecord::Migration[5.2] ,

If your application uses Rails 4.2 or lower, you will find that there is no version of Rails added in the migration file, it will look like this: ActiveRecord::Migration

The version of Rails has been added in migation since Rails 5. This basically ensures that the migration API can evolve over time without breaking the migrations generated by older versions of Rails.

To get a better understanding of this, let’s take a look at the same migration to create the users table in Rails 4.2.

If we look at the schema of the users table created by Rails 6, we can see the NOT NULL constraint for the timestamps column that exists.

This is because, starting with Rails 5 onwards, the migration API automatically adds a NOT NULL constraint to the timestamps columns without adding it to the migration file. The version of Rails in the superclass name ensures that the migration uses the migration API of the Rails version where the migration process was created. This allows Rails to maintain compatibility, as opposed to older migrations, and develop the migation API.

3. change method

The change method is a main method in a migration. When the migration is run, it calls the change method and executes the code inside it.

Along with create_table , Rails also provides another method, change_table . As the name suggests it is used to change the schema of an existing table.

In the example above, I removed the name field and added 2 fields as email string and active boolean with default value of false .

Rails also provides many other support methods that can be used such as:

  • add_column
  • remove_column
  • add_timestamps
  • rename_table

And some other methods you can find here

4. t.timestamps


We saw t.timestamps added inside migration by Rails and created two columns, created_at and updated_at . These special columns are used by Rails to track when a record is created or updated. Rails adds values ​​to these columns when the record is created and makes sure to update them when the record is updated. These columns help us track the lifetime of a record in the database.

Note: The updated_at column is not updated when we execute the update_all method in Rails. Because the update_all method will update by column rather than by row, it only updates the column we specify.

5. Revert migrations

Rails allows us to rollback the changes to the database with the following command:

This command reverts the last migration run to the database. As the above example shows, if migration has deleted the name column, then after running this command, it will add that column again.

There is also another command to rollback the previous migration and run it: rails db:redo .

Rails is smart enough to know how to reverse most migrations. But we can also provide suggestions for Rails to revert a migration using the up and down methods instead of using the change method. The up method will be used when the migration runs while the down method will be used when the migration is rollback.

In the example above, we changed the phone_number column from integer to string .

Similarly we can also write in the change method as follows:

Rails also provides another way to revert the previous migration by using the revert method as follows:

The revert method also accepts a block to revert a portion of the migration.

III. Conclude

Above is my understanding of migration in Rails, hopefully helpful for you. And if you know more about migration then don’t forget to comment below so we can better understand migration. Thank you.

Reference link:

Share the news now

Source : Viblo