rails db:migrate の使い方|マイグレーション作成・実行・ロールバックを徹底解説
Rails 開発でDBスキーマを変更する際に必須となる マイグレーション(migration)。
bin/rails db:migrate
このコマンド1つで、DBのスキーマを安全にバージョン管理しながら変更できる仕組みは、Rails が他のフレームワークと一線を画す強みです。
しかし、実務で使い始めると:
- マイグレーションファイルはどう作る?
changeとup/downの使い分けは?- ロールバック不可能なマイグレーションは?
- インデックスや外部キーはどう書く?
- 巨大テーブルに NOT NULL を追加すると本番が止まる…
- マルチDB環境での migrate コマンドは?
- ロールバックが効かないマイグレーションって?
- どのコマンドを使えば良いか覚えられない
など、知っておくべきことが多くあります。
本記事では、rails db:migrate の使い方を、リファレンスとして実用的に整理します。マイグレーション作成、change/up/down、カラム型・インデックス・外部キー、ロールバック、マルチDB対応、Zero-downtime migration、strong_migrations 活用、ありがちなミス、FAQまで完全網羅。この1本をブックマークすれば、Rails のスキーマ管理を自信を持って実践できるようになります。
- 1. 結論:今すぐ使える基本パターン10選
- 2. マイグレーションの基本構造
- 3. マイグレーションファイルの作成
- 4. change メソッドの基本
- 5. up / down メソッド(複雑な場合)
- 6. カラム型一覧
- 7. テーブル作成(create_table)
- 8. カラム操作
- 9. インデックス
- 10. 外部キー制約
- 11. NOT NULL とデフォルト値
- 12. マイグレーション内でのデータ操作
- 13. 実行コマンド完全リファレンス
- 14. マルチDB対応
- 15. Zero-downtime migration
- 16. 関連 generator
- 17. ありがちなミス・対処
- 18. よくある質問(FAQ)
- 18.1. Q1. change と up/down の使い分けは?
- 18.2. Q2. schema.rb と structure.sql どちらを使う?
- 18.3. Q3. マイグレーションの実行順序は?
- 18.4. Q4. 古いマイグレーションを削除しても良い?
- 18.5. Q5. 本番デプロイで失敗しないコツは?
- 18.6. Q6. テスト環境でのマイグレーション
- 18.7. Q7. timestamps の精度
- 18.8. Q8. UUIDを主キーにしたい
- 18.9. Q9. JSON 列の使い方
- 18.10. Q10. enum 列の使い方
- 18.11. Q11. マイグレーションのテスト
- 18.12. Q12. 失敗したマイグレーションの復旧
- 19. 参考リンク・関連資料
- 20. まとめ
結論:今すぐ使える基本パターン10選
時間がない方向けに、超頻出パターンを先に示します。
# ① マイグレーション作成(カラム追加)
bin/rails g migration AddEmailToUsers email:string
# ② テーブル作成
bin/rails g model Post title:string body:text user:references
# ③ マイグレーション実行
bin/rails db:migrate
# ④ 状態確認
bin/rails db:migrate:status
# ⑤ ロールバック(1つ)
bin/rails db:rollback
# ⑥ 複数ロールバック
bin/rails db:rollback STEP=3
# ⑦ 特定バージョンまで
bin/rails db:migrate VERSION=20260601000001
# ⑧ ダウン→アップ(再実行)
bin/rails db:migrate:redo
# ⑨ DBリセット(drop → create → migrate → seed)
bin/rails db:reset
# ⑩ test DB の準備
bin/rails db:test:prepare
詳細は以下で順に解説します。
マイグレーションの基本構造
マイグレーションファイルの命名規則
db/migrate/YYYYMMDDHHMMSS_class_name.rb
↑
UTCタイムスタンプ
例:
db/migrate/20260620100000_create_users.rb → class CreateUsers
db/migrate/20260620100100_add_email_to_users.rb → class AddEmailToUsers
タイムスタンプ部分は マイグレーションの順序を決定するキー。
最小のマイグレーションファイル
class AddEmailToUsers < ActiveRecord::Migration[8.0]
def change
add_column :users, :email, :string
end
end
| 要素 | 説明 |
|---|---|
ActiveRecord::Migration[8.0] | Rails 8.0 マイグレーションAPI |
change | 変更内容を記述するメソッド |
add_column | カラム追加のDSL |
schema_migrations テーブル
Rails は実行済みマイグレーションを内部的に管理:
SELECT version FROM schema_migrations ORDER BY version;
-- 20260620100000
-- 20260620100100
-- ...
これにより同じマイグレーションが二重実行されないようになっています。
マイグレーションファイルの作成
rails generate migration
最も基本的な作成方法:
bin/rails g migration MigrationName
# 短縮: bin/rails g migration MigrationName
db/migrate/20260620100000_migration_name.rb が生成されます。
カラム追加の慣用パターン
bin/rails g migration AddEmailToUsers email:string
→ 自動的にこう生成:
class AddEmailToUsers < ActiveRecord::Migration[8.0]
def change
add_column :users, :email, :string
end
end
命名規則 Add{Columns}To{Table} でRails が自動推測してくれます。
カラム削除の慣用パターン
bin/rails g migration RemoveEmailFromUsers email:string
→
class RemoveEmailFromUsers < ActiveRecord::Migration[8.0]
def change
remove_column :users, :email, :string
end
end
Remove{Columns}From{Table} パターン。
テーブル作成
bin/rails g model Post title:string body:text user:references
または:
bin/rails g migration CreatePosts title:string body:text
→
class CreatePosts < ActiveRecord::Migration[8.0]
def change
create_table :posts do |t|
t.string :title
t.text :body
t.references :user, null: false, foreign_key: true
t.timestamps
end
end
end
複数カラムを一気に追加
bin/rails g migration AddDetailsToUsers name:string age:integer bio:text
インデックス付きで追加
bin/rails g migration AddEmailToUsers email:string:index
→
class AddEmailToUsers < ActiveRecord::Migration[8.0]
def change
add_column :users, :email, :string
add_index :users, :email
end
end
ユニークインデックス
bin/rails g migration AddEmailToUsers email:string:uniq
→
class AddEmailToUsers < ActiveRecord::Migration[8.0]
def change
add_column :users, :email, :string
add_index :users, :email, unique: true
end
end
空のマイグレーション
bin/rails g migration UpdateUserStatus
特定パターンに当てはまらない複雑な変更は、空ファイル生成後に手動で記述。
change メソッドの基本
概要
change は マイグレーションの「アップ」処理を記述するメソッド。down(ロールバック)が自動的に推測されます。
class AddEmailToUsers < ActiveRecord::Migration[8.0]
def change
add_column :users, :email, :string
# ↑ ロールバック時は自動的に remove_column が実行される
end
end
change で自動的にロールバック可能なメソッド
| メソッド | ロールバック動作 |
|---|---|
add_column | remove_column |
add_foreign_key | remove_foreign_key |
add_index | remove_index |
add_reference | remove_reference |
add_timestamps | remove_timestamps |
change_column_default(:from:to必須) | 元に戻す |
change_column_null | 元に戻す |
create_join_table | drop_join_table |
create_table | drop_table |
disable_extension | enable_extension |
drop_join_table(block必須) | create_join_table |
drop_table(block必須) | create_table |
enable_extension | disable_extension |
remove_column(type必須) | add_column |
remove_foreign_key(to_table必須) | add_foreign_key |
remove_index | add_index |
remove_reference | add_reference |
remove_timestamps | add_timestamps |
rename_column | 元の名前に戻す |
rename_index | 元の名前に戻す |
rename_table | 元の名前に戻す |
change で動かないパターン
# ❌ remove_column の type省略はロールバック不可
def change
remove_column :users, :email # ロールバック時の型情報なし
end
# ✅ 型を指定すればOK
def change
remove_column :users, :email, :string
end
# ❌ change_column はロールバック不可能(元の型が分からない)
def change
change_column :users, :name, :text # 元は何だったか不明
end
# ✅ up/down を分ける
def up
change_column :users, :name, :text
end
def down
change_column :users, :name, :string
end
up / down メソッド(複雑な場合)
ロールバックを明示的に制御したい場合は change の代わりに up / down:
class ComplexMigration < ActiveRecord::Migration[8.0]
def up
# フォワード処理
add_column :users, :status, :integer, default: 0
User.update_all(status: 1)
end
def down
# ロールバック処理
remove_column :users, :status
end
end
IrreversibleMigration
データ変換でロールバック不可能な場合:
class RemoveEmptyTags < ActiveRecord::Migration[8.0]
def up
Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
end
def down
raise ActiveRecord::IrreversibleMigration, "Can't recover deleted tags"
end
end
ロールバック時には明示的にエラーを上げる。
reversible ブロック
change 内で部分的に up/down を分ける場合:
class UpdateUserStatus < ActiveRecord::Migration[8.0]
def change
reversible do |dir|
dir.up do
execute "UPDATE users SET status = 1 WHERE active = true"
end
dir.down do
execute "UPDATE users SET active = (status = 1)"
end
end
end
end
カラム型一覧
Rails が標準でサポートする型:
| 型 | 用途 | DB対応 |
|---|---|---|
:string | 短文字列(255文字) | VARCHAR |
:text | 長文字列 | TEXT |
:integer | 整数 | INT |
:bigint | 大整数(64bit) | BIGINT |
:float | 浮動小数点 | FLOAT |
:decimal | 精密小数(精度指定) | DECIMAL |
:numeric | decimalのエイリアス | NUMERIC |
:datetime | 日時 | TIMESTAMP / DATETIME |
:timestamp | 日時(datetime同等) | TIMESTAMP |
:time | 時刻 | TIME |
:date | 日付 | DATE |
:binary | バイナリ | BLOB / BYTEA |
:boolean | 真偽値 | BOOLEAN / TINYINT |
:json | JSON | JSON |
:jsonb | JSONB(PostgreSQL) | JSONB |
:uuid | UUID | UUID |
:references | 関連(外部キー) | INTEGER + foreign_key |
型オプション
add_column :products, :price, :decimal, precision: 10, scale: 2
add_column :users, :role, :integer, default: 0, null: false
add_column :articles, :tags, :string, array: true, default: [] # PostgreSQL専用
add_column :records, :metadata, :jsonb, default: {} # PostgreSQL専用
テーブル作成(create_table)
基本
create_table :products do |t|
t.string :name
t.text :description
t.decimal :price, precision: 10, scale: 2
t.boolean :active, default: true
t.references :user, null: false, foreign_key: true
t.timestamps # created_at, updated_at
end
主キー指定
# id を別の型にする
create_table :products, id: :uuid do |t|
t.string :name
end
# id を作らない
create_table :join_table, id: false do |t|
t.integer :user_id
t.integer :role_id
end
# 主キーを変える
create_table :products, primary_key: :sku do |t|
t.string :sku
t.string :name
end
関連(references)
create_table :posts do |t|
t.references :user, foreign_key: true, null: false
# 自動的に:
# - user_id カラム作成
# - インデックス作成
# - 外部キー制約
end
ポリモーフィック関連
create_table :comments do |t|
t.references :commentable, polymorphic: true, null: false
# commentable_id, commentable_type の2カラム作成
end
Self-referential
create_table :employees do |t|
t.string :name
t.references :manager, foreign_key: { to_table: :employees }
end
join table(多対多)
create_join_table :users, :roles do |t|
t.index [:user_id, :role_id]
end
# user_id, role_id の2カラムのみ作成
カラム操作
add_column(追加)
add_column :users, :email, :string
add_column :users, :age, :integer, default: 0, null: false
add_column :users, :status, :integer, default: 0, index: true
remove_column(削除)
remove_column :users, :email, :string
# 型を指定するとロールバック可能
# 複数同時に削除
remove_columns :users, :email, :phone
# ⚠️ Rails 8 ではこの形式の change での自動リバーシブルは限定的
rename_column(リネーム)
rename_column :users, :email, :email_address
change_column(型変更)
change_column :users, :name, :text
change_column :users, :age, :integer, limit: 8 # bigint化
⚠️ change メソッド内では使えない(ロールバック不可)。up/down を分けるか reversible で対応。
change_column_default(デフォルト変更)
# change で使える書き方
change_column_default :users, :status, from: 0, to: 1
change_column_null(NULL制約変更)
change_column_null :users, :email, false # NOT NULL にする
change_column_null :users, :email, true # NULL 許可
⚠️ 既にデータがあり、NOT NULLにできない場合は事前にデータをクリーン化する必要あり。
インデックス
基本
# 単一カラム
add_index :users, :email
# ユニーク
add_index :users, :email, unique: true
# 複合
add_index :posts, [:user_id, :created_at]
# 名前指定
add_index :users, :email, name: "index_users_on_email_unique", unique: true
# 部分インデックス(PostgreSQL)
add_index :users, :email, where: "active = true"
# 関数インデックス
add_index :users, "lower(email)", name: "index_users_on_lower_email"
コンカレント追加(PostgreSQL)
巨大テーブルへのインデックス追加でテーブルロックを避ける:
class AddIndexToUsersEmail < ActiveRecord::Migration[8.0]
disable_ddl_transaction! # ← 必須
def change
add_index :users, :email, algorithm: :concurrently
end
end
disable_ddl_transaction! でトランザクション無効化。algorithm: :concurrently でブロッキングを最小化。
インデックス削除
remove_index :users, :email
remove_index :users, name: "index_users_on_email_unique"
外部キー制約
add_foreign_key
add_foreign_key :posts, :users
# posts.user_id → users.id
# カラム名指定
add_foreign_key :posts, :users, column: :author_id
# 削除動作
add_foreign_key :posts, :users, on_delete: :cascade
add_foreign_key :posts, :users, on_delete: :nullify
add_foreign_key :posts, :users, on_delete: :restrict
references で同時作成
add_reference :posts, :user, foreign_key: true, null: false
# user_id カラム + インデックス + 外部キー
削除
remove_foreign_key :posts, :users
remove_foreign_key :posts, column: :author_id
NOT NULL とデフォルト値
デフォルト値付き
add_column :users, :role, :integer, default: 0
NOT NULL
add_column :users, :email, :string, null: false
⚠️ 既存データがある場合、デフォルトなしで NOT NULL 追加すると失敗:
# ❌ 既存データ全部に NULL → エラー
add_column :users, :email, :string, null: false
# ✅ デフォルト値で全行を埋めてから NOT NULL
add_column :users, :email, :string, default: "", null: false
Zero-downtime での NOT NULL 追加(巨大テーブル向け)
3段階に分ける:
# Step 1: カラム追加(nullable)
class AddEmailToUsersStep1 < ActiveRecord::Migration[8.0]
def change
add_column :users, :email, :string
end
end
# Step 2: アプリ側でデフォルト値設定 + データ移行ジョブ実行
# Step 3: NOT NULL 制約追加
class AddEmailToUsersStep3 < ActiveRecord::Migration[8.0]
def change
change_column_null :users, :email, false
end
end
マイグレーション内でのデータ操作
execute(生SQL)
class UpdateUserStatuses < ActiveRecord::Migration[8.0]
def up
execute "UPDATE users SET status = 1 WHERE active = true"
end
def down
execute "UPDATE users SET status = 0"
end
end
ActiveRecord モデルを使う
class UpdateUserStatuses < ActiveRecord::Migration[8.0]
def up
# ⚠️ マイグレーション内では本物のモデルを使わない
say_with_time "Updating user statuses..." do
User.reset_column_information
User.where(active: true).update_all(status: 1)
end
end
end
⚠️ マイグレーション内で本物のモデルクラスを使うのは推奨されない。理由:
- マイグレーションは過去のスキーマで動く可能性
- モデルクラスが将来削除・改名されると古いマイグレーションが壊れる
一時的なモデル定義
class UpdateUserStatuses < ActiveRecord::Migration[8.0]
class MigrationUser < ActiveRecord::Base
self.table_name = "users"
end
def up
MigrationUser.where(active: true).update_all(status: 1)
end
end
実行コマンド完全リファレンス
基本
# 保留マイグレーション全実行
bin/rails db:migrate
# 環境指定
bin/rails db:migrate RAILS_ENV=production
RAILS_ENV=test bin/rails db:migrate
状態確認
bin/rails db:migrate:status
出力例:
database: myapp_development
Status Migration ID Migration Name
--------------------------------------------------
up 20260101000001 Create users
up 20260102000001 Create posts
down 20260601000001 Add email to users ← 保留
ロールバック
# 直前の1つを戻す
bin/rails db:rollback
# 3つ戻す
bin/rails db:rollback STEP=3
特定バージョンへ
# そのバージョンまで進める
bin/rails db:migrate VERSION=20260601000001
# そのバージョンまで戻す(含まない)
bin/rails db:rollback VERSION=20260601000001
個別 up/down
# 特定バージョンを up
bin/rails db:migrate:up VERSION=20260601000001
# 特定バージョンを down
bin/rails db:migrate:down VERSION=20260601000001
redo(やり直し)
# 直前の1つを down → up
bin/rails db:migrate:redo
# 2つ
bin/rails db:migrate:redo STEP=2
スキーマ操作
# schema.rb からロード(マイグレーション履歴なしに再構築)
bin/rails db:schema:load
# schema.rb を現在のDB状態から再生成
bin/rails db:schema:dump
リセット系
# DB完全リセット(drop + create + schema:load + seed)
bin/rails db:reset
# 同上(drop + create + migrate + seed)
bin/rails db:setup
# DB作成のみ
bin/rails db:create
# DB削除のみ
bin/rails db:drop
# 安全な選択肢(作成 or 既存ならスキップ)
bin/rails db:prepare
test 環境
# test DB を最新スキーマに
bin/rails db:test:prepare
# test DB を完全クリーン
bin/rails db:test:purge
seed
# db/seeds.rb 実行
bin/rails db:seed
マルチDB対応
Rails 6+ では複数DB管理が標準化。
database.yml
production:
primary:
<<: *default
database: myapp_production
cache:
<<: *default
database: myapp_cache
migrations_paths: db/cache_migrate
queue:
<<: *default
database: myapp_queue
migrations_paths: db/queue_migrate
マルチDB専用コマンド
# 全DB分実行
bin/rails db:migrate
# 特定DBのみ
bin/rails db:migrate:primary
bin/rails db:migrate:cache
bin/rails db:migrate:queue
# 状態確認
bin/rails db:migrate:status
bin/rails db:migrate:status:cache
# ロールバック
bin/rails db:rollback:primary
bin/rails db:rollback:cache
特定DBへのマイグレーション作成
bin/rails g migration CreateCacheEntries --database cache
# db/cache_migrate/ 配下に生成される
詳細はSolid Queue 使い方、Solid Cache 使い方、Solid Cable 使い方 も参照。
Zero-downtime migration
本番サービスを止めずにスキーマ変更するためのテクニック。
1. 巨大テーブルのインデックス追加
class AddIndexToUsersEmail < ActiveRecord::Migration[8.0]
disable_ddl_transaction!
def change
add_index :users, :email, algorithm: :concurrently
end
end
2. NOT NULL の段階的追加
# Step 1: カラム追加(nullable, デフォルト値あり)
add_column :users, :email_verified, :boolean, default: false
# Step 2: 既存データ更新(マイグレーション or バックグラウンドジョブ)
# Step 3: NOT NULL 制約追加
change_column_null :users, :email_verified, false
3. カラム削除の段階的処理
# Step 1: モデルから削除(コードでアクセスしない)
# class User < ApplicationRecord
# self.ignored_columns = ["old_column"]
# end
# Step 2: デプロイして既存リクエストでもアクセスされないことを確認
# Step 3: カラム削除マイグレーション
def change
remove_column :users, :old_column, :string
end
4. カラム rename を避ける
# ❌ ダウンタイムリスクあり
rename_column :users, :name, :full_name
# ✅ 段階的に
# 1. 新カラム追加 (full_name)
# 2. データコピー
# 3. アプリで新旧両方アクセス可能に
# 4. 古いカラム削除
5. strong_migrations gem
# Gemfile
gem "strong_migrations"
危険なマイグレーションを検知し、修正方法を提示してくれます:
=== Dangerous operation detected ===
Adding a column with a non-null default requires that existing rows be updated.
Instead:
1. Add the column without a default value
2. Backfill the column
3. Change the default
関連 generator
model 生成
bin/rails g model User name:string email:string
# → app/models/user.rb
# → db/migrate/xxx_create_users.rb
# → test/models/user_test.rb
# → test/fixtures/users.yml
resource 生成
bin/rails g resource Post title:string body:text
# → モデル + マイグレーション + コントローラ + ルーティング
scaffold 生成
bin/rails g scaffold Post title:string body:text
# → モデル + マイグレーション + コントローラ + ビュー + ルーティング + テスト
ありがちなミス・対処
1. 既存マイグレーションを編集してしまう
# db/migrate/20260101000001_create_users.rb
# 直接編集 → 既に migrate 済みのため、変更が反映されない
対処: 新しいマイグレーションを作って変更:
bin/rails g migration ChangeUsersFooColumn
または、ローカルで一旦ロールバックしてから編集:
bin/rails db:rollback
# 編集
bin/rails db:migrate
⚠️ 既にチームでpush済みのマイグレーションの編集は NG。
2. ロールバック不可能なマイグレーション
def change
remove_column :users, :email # 型不明 → IrreversibleMigration
end
対処: 型を指定
def change
remove_column :users, :email, :string
end
3. 巨大テーブルへの NOT NULL 追加でサービス停止
def change
add_column :users, :email, :string, null: false
# 既存100万行の users にエラー
end
対処: 段階的に追加(前述のZero-downtime参照)。
4. データ移行とスキーマ変更を混在
# ❌ スキーマ + データ更新 + 別スキーマ変更 → 失敗時の復旧難
def change
add_column :users, :status, :integer
User.update_all(status: 0)
remove_column :users, :active
end
対処: マイグレーションを分割
# 1. add_column
# 2. データ移行ジョブ
# 3. remove_column
5. timestamps 忘れ
create_table :products do |t|
t.string :name
# t.timestamps が無い → created_at, updated_at がない
end
対処: 後から追加
add_timestamps :products, default: -> { 'CURRENT_TIMESTAMP' }
change_column_default :products, :created_at, from: nil, to: nil
change_column_default :products, :updated_at, from: nil, to: nil
または最初から含める:
create_table :products do |t|
t.string :name
t.timestamps # ← 必須
end
6. references の foreign_key 忘れ
# ❌ ID カラムだけ、外部キー制約なし
t.references :user
# ✅ 外部キー制約も追加
t.references :user, null: false, foreign_key: true
7. インデックス未付与でクエリ遅延
# email でログイン検索するのに index なし
add_column :users, :email, :string
# → User.find_by(email: ...) が遅い
対処:
add_index :users, :email, unique: true
8. PendingMigrationError 発生
詳細はActiveRecord::PendingMigrationError の記事。
よくある質問(FAQ)
Q1. change と up/down の使い分けは?
| 状況 | 推奨 |
|---|---|
| シンプルな add/remove/create | change |
| 複雑なロジック・データ変換 | up/down |
| ロールバック不可能な処理 | up/down(down で raise) |
Q2. schema.rb と structure.sql どちらを使う?
| 選択肢 | 用途 |
|---|---|
schema.rb(デフォルト) | DB非依存、シンプル |
structure.sql | PostgreSQL拡張、複雑な制約使用時 |
# config/application.rb
config.active_record.schema_format = :sql # structure.sql 使用
Q3. マイグレーションの実行順序は?
ファイル名先頭のタイムスタンプ(UTC)順。手動で書き換えてはダメ。
複数人が同時に作成する場合、ファイル名のタイムスタンプ衝突に注意。
Q4. 古いマイグレーションを削除しても良い?
OK だが慎重に:
- 削除後は
db:schema:loadでしか新規DBを構築できなくなる - 既存環境への影響なし(schema_migrations が記録)
新規開発者向けに README に bin/rails db:schema:load 推奨を明記。
Q5. 本番デプロイで失敗しないコツは?
- ステージングで事前テスト
- strong_migrations で危険検知
- Zero-downtime 設計
- バックアップ取得
- デプロイスクリプトに
db:migrate含める
Q6. テスト環境でのマイグレーション
# CI セットアップで
bin/rails db:test:prepare
# または
bin/rails db:schema:load RAILS_ENV=test
Q7. timestamps の精度
PostgreSQL では microsecond 精度ですが、Rails の t.timestamps はデフォルトで 6桁の精度:
t.timestamps # precision: 6 がデフォルト(Rails 7+)
明示変更も可能:
t.timestamps precision: 3 # ミリ秒
Q8. UUIDを主キーにしたい
PostgreSQL 拡張を有効化:
enable_extension "pgcrypto"
create_table :products, id: :uuid do |t|
t.string :name
end
または Rails 7.1+ なら:
create_table :products, id: :uuid, default: -> { "gen_random_uuid()" } do |t|
t.string :name
end
Q9. JSON 列の使い方
# PostgreSQL: jsonb 推奨(インデックス可能)
add_column :products, :metadata, :jsonb, default: {}
# MySQL: json
add_column :products, :metadata, :json
# 利用
product.metadata = { tags: ["new", "sale"], expires_at: "2026-12-31" }
product.metadata["tags"]
Q10. enum 列の使い方
# integer カラムで実装
add_column :users, :status, :integer, default: 0, null: false
# モデル側
class User < ApplicationRecord
enum :status, { pending: 0, active: 1, banned: 2 }
end
User.active # WHERE status = 1
user.pending?
user.active!
Q11. マイグレーションのテスト
# spec/migrations/xxx_spec.rb
require 'rails_helper'
RSpec.describe "AddEmailToUsers", type: :migration do
# 検証
end
gem 'rails-controller-testing' 等で支援。実務ではあまりやらない。
Q12. 失敗したマイグレーションの復旧
# 状態確認
bin/rails db:migrate:status
# down のままならファイル修正後 migrate
# up になっていて変更が不完全なら、ロールバックして修正後 migrate
bin/rails db:rollback
# ファイル修正
bin/rails db:migrate
DB が壊れたらバックアップから復旧。
参考リンク・関連資料
Rails 公式
- Active Record Migrations(Guide) – 公式マイグレーションガイド
- Multiple Databases with Active Record(Guide) – マルチDB
- ActiveRecord::Migration(API doc) – APIリファレンス
関連 Gem
- strong_migrations – 安全なマイグレーション
- online_migrations – Zero-downtime
- lol_dba – 未付与インデックス検出
- scenic – DB ビュー管理
関連記事(本サイト)
- ActiveRecord::PendingMigrationError 対処 – マイグレーション保留エラー
- undefined method nil:NilClass – Rails エラー系シリーズ
- ActiveRecord::RecordNotFound – 同上
- ActionController::RoutingError – 同上
- NameError uninitialized constant – 同上
- Rails 8 アップグレードガイド – Rails 8 全般
- Solid Queue 使い方 – マイグレーション関連
- Solid Cache 使い方 – 同上
- Solid Cable 使い方 – 同上
- MySQL 1146 Table doesn’t exist – DB関連エラー
まとめ
rails db:migrate は Rails 開発の基礎ですが、奥が深いツール。要点を再整理します。
- 基本構造:
db/migrate/YYYYMMDDHHMMSS_migration_name.rbファイル +ActiveRecord::Migration[8.0]継承クラス - 作成:
rails g migrationでテンプレ生成、命名規約で自動生成も可能 - 記述:
changeメソッド(シンプル)またはup/down(複雑) - カラム型: string/text/integer/decimal/datetime/json/jsonb/uuid 等
- テーブル操作:
create_table、add_column、add_index、add_foreign_key - 実行:
db:migrate、状態確認はdb:migrate:status - ロールバック:
db:rollback、特定バージョンはVERSION=... - マルチDB:
db:migrate:cache、db:migrate:queue等の専用コマンド - Zero-downtime: コンカレントインデックス、段階的 NOT NULL、ignored_columns
- 安全策:
strong_migrations、ステージング検証、バックアップ - 避けるべき: 既存マイグレーションの編集、巨大データへの NOT NULL、複雑な混在処理
これらの知識は、Rails アプリの設計・開発・運用・本番デプロイすべてで活用できます。本記事をブックマークしておけば、db:migrate 関連のあらゆる作業を効率化できます。
本記事は2026年6月時点の情報をもとに、Ruby on Rails 7.x / 8.x での動作確認・公式ドキュメントに基づき作成しています。Rails のバージョンによって挙動が異なる場合があるため、最新の情報はRails公式ガイドもあわせてご確認ください。
-
前の記事
Linuxでコマンドの実行時間を計測する方法|timeコマンド完全解説 2026.06.26
-
次の記事
Linux unzipコマンドで展開先ディレクトリを指定する方法|オプション一覧と実用例を徹底解説 2026.06.26
コメントを書く