Skip to content

Ror Migrations

DodaTech 3 min read

title: Ruby on Rails Migrations — Complete Guide to Database Schema Changes description: 'Learn Ruby on Rails migrations: creating tables, adding columns, indexes, data migrations, rollbacks, seeds, and production migration strategies.' date: 2026-06-28 lastmod: 2026-06-28 weight: 19 tags: [backend, ror]


Ruby on Rails migrations provide a DSL for managing database schema changes in version-controlled Ruby code, enabling consistent database evolution across environments.

## What You'll Learn

By the end of this tutorial, you'll create and run migrations, add/remove columns and indexes, implement reversible data migrations, seed databases, and apply migrations safely in production.

## Real-World Use

A team of 5 developers works on a Rails app. Each developer creates migrations for their features. CI applies all pending migrations. Production migrations run during deployment windows.

## Migrations Learning Path

```mermaid
flowchart LR
  A[Active Record] --> B[Migrations]
  B --> C[Validations]
  C --> D[Associations]
  D --> E[Forms]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

Creating Migrations

rails generate migration CreateProducts
rails generate migration AddPriceToProducts
rails generate migration RemoveOldColumnFromProducts
# db/migrate/20260628000001_create_products.rb
class CreateProducts < ActiveRecord::Migration[7.1]
  def change
    create_table :products do |t|
      t.string :name, null: false
      t.text :description
      t.decimal :price, precision: 10, scale: 2, null: false
      t.references :category, null: false, foreign_key: true
      t.boolean :active, default: true
      t.timestamps
    end
    add_index :products, :name
    add_index :products, [:category_id, :active]
  end
end

Column Operations

class AddDetailsToProducts < ActiveRecord::Migration[7.1]
  def change
    add_column :products, :sku, :string
    add_column :products, :stock_count, :integer, default: 0
    change_column :products, :price, :decimal, precision: 12, scale: 2
    rename_column :products, :description, :long_description
    remove_column :products, :obsolete_field, :string
  end
end

Indexes

class AddIndexes < ActiveRecord::Migration[7.1]
  def change
    add_index :users, :email, unique: true
    add_index :orders, :user_id
    add_index :orders, [:status, :created_at]
    add_index :posts, :title, using: :gin, opclass: :gin_trgm_ops
  end
end

Data Migrations

class BackfillProductSlugs < ActiveRecord::Migration[7.1]
  def up
    Product.where(slug: nil).find_each do |product|
      product.update!(slug: product.name.parameterize)
    end
  end
  def down
    # Cannot reverse data changes
    raise ActiveRecord::IrreversibleMigration
  end
end

Seeds

# db/seeds.rb
puts "Seeding database..."
# Create admin user
User.find_or_create_by!(email: "admin@example.com") do |user|
  user.username = "admin"
  user.password = "password123"
  user.role = :admin
end
# Create categories
["Electronics", "Clothing", "Books"].each do |name|
  Category.find_or_create_by!(name: name)
end
puts "Seeding complete!"
rails db:seed
# Or reset + seed
rails db:seed:replant

Common Mistakes

1. Editing Existing Migrations

Once a migration is merged and deployed, never edit it. Create a new migration to undo or modify.

2. Irreversible Migrations Without Down

Always provide a down method or use change with reversible operations. Otherwise, rollbacks fail.

3. Large Data Migrations in Production

Backfilling millions of records locks tables. Use batch processing with find_each.

4. Missing Indexes

Foreign keys and frequently queried columns need indexes. Add them in the same migration as the column.

5. Not Testing Migrations

Test migrations on a copy of production data. A bad migration can cause downtime.

Practice Questions

1. What is a Rails migration?

A Ruby file describing database schema changes. Up applies changes, Down reverts them.

2. How do I add a column with a default value?

add_column :products, :stock_count, :integer, default: 0.

3. What is the difference between up/down and change?

change auto-detects reversible operations. up/down is needed for operations Rails can't reverse.

4. How do you run migrations in production?

rails db:migrate RAILS_ENV=production. Or generate SQL with rails db:migrate:sql.

5. Challenge: Create a migration that adds a slug column to posts, indexes it, and backfills existing records.

class AddSlugToPosts < ActiveRecord::Migration[7.1]
  def change
    add_column :posts, :slug, :string
    add_index :posts, :slug, unique: true
    reversible do |dir|
      dir.up { Post.find_each { |p| p.update(slug: p.title.parameterize) } }
    end
  end
end

FAQ

Can I rename a migration file?

No. The timestamp prefix determines order. Create a new migration instead.

How do I check migration status?

rails db:migrate:status shows which migrations are up/down.

What happens if two developers create migrations with the same timestamp?

One developer rebases. The migration with the later timestamp runs first.

How do I roll back a migration?

rails db:rollback rolls back one migration. STEP=3 rolls back three.

Can I seed data as part of a migration?

Yes but prefer db/seeds.rb for seed data. Use migrations only for data backfills required by schema changes.

Mini Project: Complete Migration Workflow

Create tables, add columns, indexes, and seed data for a blog app.

rails generate migration CreatePosts title:string body:text published:boolean
rails generate migration AddSlugToPosts slug:string:uniq
rails generate migration CreateComments body:text post:references
rails db:migrate
rails db:seed

What's Next

Ruby on Rails Validations Ruby on Rails Associations

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro