Ror Migrations
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
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