Ruby on Rails - Migrations



Rails Migration allows you to use Ruby to define changes to your database schema, making it possible to use a version control system to keep things synchronized with the actual code. Instead of writing schema modifications in pure SQL, you can use a Ruby Domain Specific Language (DSL) to make required changes to your table structure.

This has many uses, including –

  • Teams of Developers − If one person makes a schema change, the other developers just need to update, and run "rake migrate".
  • Production Servers − Run "rake migrate" when you roll out a new release to bring the database up to date as well.
  • Multiple Machines − If you develop on both a desktop and a laptop, or in more than one location, migrations can help you keep them all synchronized.

Migration acts as a new 'version' of the database. When you generate a model, a schema has nothing in it. Each migration modifies it to add or remove tables, columns, or indexes.

What Can Rails Migration Do?

  • create_table(name, options)
  • drop_table(name)
  • rename_table(old_name, new_name)
  • add_column(table_name, column_name, type, options)
  • rename_column(table_name, column_name, new_column_name)
  • change_column(table_name, column_name, type, options)
  • remove_column(table_name, column_name)
  • add_index(table_name, column_name, index_type)
  • remove_index(table_name, column_name)

Migrations support all the basic data types − The following is the list of data types that migration supports −

  • string − for small data types such as a title.
  • text − for longer pieces of textual data, such as the description.
  • integer − for whole numbers.
  • float − for decimals.
  • datetime and timestamp − store the date and time into a column.
  • date and time − store either the date only or time only.
  • binary − for storing data such as images, audio, or movies.
  • Boolean − for storing true or false values.

Valid column options are − The following is the list of valid column options.

  • comment − Adds a comment for the column.
  • collation − Specifies the collation for a string or text column.
  • default − Allows to set a default value on the column. Use nil for NULL. (:default => "blah")
  • limit − Sets the maximum number of characters for a string column and the maximum number of bytes for text/binary/integer columns. (:limit => "50")
  • null − Allows or disallows NULL values in the column. (:null => false)
  • precision − Specifies the precision for decimal/numeric/datetime/time columns.
  • scale − specifies the scale for the decimal and numeric columns.

Create the Migrations

In the previous chapter, you have created Book and Subject models with the following commands −

malhar@ubuntu:~/library$ rails generate model Book title:string price:float subject:references
malhar@ubuntu:~/library$ rails generate model Subject name:string

Note that using subject:references in the Book model automatically creates a subject_id foreign key column in the books table.

Migration files are created inside the db/migrate folder, one for each migration class. The name of the file is of the form YYYYMMDDHHMMSS_create_books.rb, which has the following code −

class CreateBooks < ActiveRecord::Migration[8.0]
  def change
    create_table :books do |t|
      t.string :title
      t.float :price
      t.references :subject, null: false, foreign_key: true
      t.timestamps
    end
  end
end

Similarly, the create_subjects.rb file in db\migrate folder has the following code −

class CreateSubjects < ActiveRecord::Migration[8.0]
  def change
    create_table :subjects do |t|
      t.string :name
      t.timestamps
    end
  end
end

Make sure that you have created associations between Book and Subject model. The Book class in book.rb file has belongs_to relation with subjects

class Book < ApplicationRecord
  belongs_to :subject
end

Similarly, there is a has_many relationship between Book and subjects (subject.rb)

class Subject < ApplicationRecord
  has_many :books
end

NOTE − Before running the migration generator, it is recommended to clean the existing migrations generated by model generators.

The db:migrate command

Now that you have created all the required migration files. It is time to execute them against the database. To do this, go to a command prompt and go to the library directory in which the application is located, and then run the rails migrate command as follows −

malhar@ubuntu:~/library$ rails db:migrate
== 20250305181938 CreateBooks: migrating ======================================
-- create_table(:books)
   -> 0.0188s
== 20250305181938 CreateBooks: migrated (0.0054s)===============================
== 20250305182034 CreateSubjects: migrating ===================================
-- create_table(:subjects)
   -> 0.0069s
== 20250305182034 CreateSubjects: migrated (0.0084s) ==========================

Rails creates db\schema.rb file to define the structure of the tables in the database.

ActiveRecord::Schema[8.0].define(version: 2025_03_05_182034) do
  create_table "books", force: :cascade do |t|
    t.string "title"
    t.float "price"
    t.integer "subject_id", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["subject_id"], name: "index_books_on_subject_id"
  end
  create_table "subjects", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
  add_foreign_key "books", "subjects"
end

The migration step creates a db/seeds.rb file is used to populate the database with initial or default data when setting up a Rails application.

Edit the file and add the following statement in it −

Subject.create([
  { name: "Physics" },
  { name: "Mathematics" },
  { name: "Chemistry" },
  { name: "Psychology" },
  { name: "Geology" }
])

and then run −

malhar@ubuntu:~/library$ rails db:seed

This inserts the records in the Subject table.

generate migration

This command is used to modify the structure of an existing table, such as adding or removing a column.

Adding Columns

When you want to add a new column to an existing table in your database, you can use a migration with the format "AddColumnToTable" followed by a list of column names and types.

To add a new column named author in the book model, use the following command −

malhar@ubuntu:~/library$ rails generate migration AddAuthorToBooks author:string

This creates a migration file −

class AddAuthorToBooks < ActiveRecord::Migration[8.0]
  def change
    add_column :books, :author, :string
  end
end

You then apply it using the migrate command again:

malhar@ubuntu:~/library$ rails db:migrate

Removing Columns

Similarly, if the migration name is of the form "RemoveColumnFromTable" and is followed by a list of column names

malhar@ubuntu:~/library$ rails generate migration RemoveAuthorFromBooks author:string

The change() Method

Whenever a model structure is altered, the migration command defines the change() method to perform corresponding action (add_column, remove_column etc). It supports the following actions −

  • add_column
  • add_foreign_key
  • add_index
  • add_reference
  • create_join_table
  • create_table
  • drop_table
  • remove_column
  • remove_foreign_key
  • remove_index
  • remove_reference
  • remove_timestamps
  • rename_column
  • rename_index
  • rename_table

You can also use the up and down methods instead of the change method (change method was introduced in Rails 5.0, and is the standard way to modify the migrations, although up/down methods are still supported but not recommended).

The method up is used when migrating to a new version, down is used to roll back any changes if needed.

Other Migration Commands

In addition to the rails db:migrate command, the following migration commands are useful.

Rolling Back

If you have made a mistake in the model definition, rather than tracking down the version number associated with the previous migration you can run:

malhar@ubuntu:~/library$ rails db:rollback

This will roll back the ldatabase to the latest migration, either by reverting the change method or by running the down method. If you need to undo several migrations you can provide a STEP parameter:

malhar@ubuntu:~/library$ rails db:rollback STEP=2

Setting Up the Database

The rails db:setup command will create the database, load the schema, and initialize it with the seed data.

Resetting the Database

The rails db:reset command will drop the database and set it up again. This is equivalent to rails db:drop db:setup command.

Advertisements