【Rails】マイグレーションの書き方《実行篇》

はじめに

ActiveRecordの機能のひとつ、マイグレーションは便利な機能ですが、使い方を間違えるとせっかく作ったデータベースを破壊してしまいかねません。データベースの操作を間違えたときに有用なロールバックも、きちんと手順を守って行わないとマイグレーションの整合性が崩れてしまう可能性があります。

本記事では、マイグレーションの実行についてまとめています。

なお、マイグレーションの作成・編集については以下の記事でまとめていますので、併せてご覧いただければと思います。

マイグレーションの実行

ステータスコマンド

現在のマイグレーションがどこまで実行されているかなどをコマンドで確認することができます。特にチーム開発を行っているときやロールバックを行う前には必ず実行することをおすすめします。

$ rails db:migrate:status
database: db/development.sqlite3

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190808140406  Create articles
   up     20190810152518  Add category to articles
   up     20190812090038  Add picture to articles

Statusがupならマイグレーションが実行されている、downならされていないという意味になります。Migration IDは、後述する特定のマイグレーションの実行などで必要となるバージョンです。

マイグレートコマンド

作成したマイグレーションを実行しデータベースの操作を行うコマンドです。最もよく使うコマンドだと思います。

$ rails db:migrate

特定のマイグレーションまで実行したい場合、マイグレーションのバージョンを指定することもできます。

$ rails db:migrate VERSION=20190812090038

このコマンドを実行すると、指定したバージョンを含むそれまでのマイグレーションがすべて実行されます。指定したバージョンが先の場合すべてのバージョンをupにし、前の場合すべてのバージョンをdownにします。

特定のマイグレーションだけをupまたはdownにすることもできます。

$ rails db:migrate:up VERSION=20190812090038
$ rails db:migrate:down VERSION=20190812090038

ロールバックコマンド

一度行ったマイグレーションを取り消したい場合、ロールバックコマンドを実行します。以下のコマンドは直近のマイグレーションだけを取り消します。

$ rails db:rollback

いくつかのマイグレーションを一気に取り消す場合、取り消すマイグレーション数を指定することもできます。

$ rails db:rollback STEP=5

このコマンドは直近から5世代前までのマイグレーションがすべて取り消されます。

トラブルシューティング

マイグレーションについてきちんと理解していないうちは、マイグレーションの実行周りでトラブルが起こりがちです。大抵は無理解からくる自分のミスが原因なわけですが、トラブルが起こったときは混乱して右往左往してしまいます。

マイグレーションを実行する際によく起こるであろうトラブルとそのベストプラクティスについてまとめてみました。

マイグレーションを修正したい場合

例えば、マイグレーションファイル作成時にカラム名を間違って記述してしまい、気付かないままマイグレーションを実行してしまった場合。最も簡単な方法は、ロールバックコマンドを実行してマイグレーションを取り消し、マイグレーションファイルを正しく修正してからもう一度マイグレーションを実行することです。

# マイグレートを取り消し
$ rails db:rollback

# マイグレーションファイルを修正
$ vi db/migrate/20190812090038_add_picture_to_articles.rb

# 再度、マイグレートを実行
$ rails db:migrate

では、間違ったマイグレーションが直近ではなくもっと前の世代だった場合はどうでしょうか。現在のマイグレーションと間違ったマイグレーションの間に正しいマイグレーションがいくつも存在している状態です。

この場合は、ステータスコマンドで間違ったマイグレーションまでの世代数を確認し、ロールバックコマンドでその世代までのマイグレーションをすべて取り消します。あとはマイグレーションファイルを正しく修正してからもう一度マイグレーションを実行します。

# ステータスを確認
$ rails db:migrate:status

# 世代を指定してマイグレートを取り消し
$ rails db:rollback STEP=5

# マイグレーションファイルを修正
$ vi db/migrate/20190812090038_add_picture_to_articles.rb

# 再度、マイグレートを実行
$ rails db:migrate

あるいは、間違いを修正するためのマイグレーションファイルを新たに作成するという方法もあります。カラム名の間違いくらいだったら、rename_columnを使って簡単に修正することができます。

# マイグレーションファイルを作成
$ rails generate migration RenameColumnFromArticles

# 作成したマイグレーションファイルを編集
$ vi db/migrate/20190814110732_rename_column_from_articles.rb

# マイグレーションを実行
$ rails:migrate

カラム名を修正するマイグレーションファイル。

class RenameColumnFromArticles < ActiveRecord::Migration
  def change
    rename_column :articles, :content, :body
  end
end

この方法ならロールバックする必要はありません。常に前進し続けるというスタイルです。デメリットとしては、ロールバックする場合と比べてマイグレーションの数が肥大化しがちだということです。その結果、デプロイ時などにマイグレーションが一気に実行されると時間がかかりすぎることに繋がります。

マイグレーションを削除したい場合

例えば、追加したカラムが不要になったので削除したい場合。通常であれば、カラムを削除するマイグレーションファイルを作成してマイグレーションを実行するという方法で十分でしょう。

# マイグレーションファイルを作成
$ rails generate migration RemoveCategoryFromArticles category:string

# マイグレートを実行
$ rails db:migrate

カラムを削除するマイグレーションファイル。

class RemoveCategoryFromArticles < ActiveRecord::Migration
  def change
    remove_column :articles, :category
  end
end

しかし、何らかの理由によりカラムを追加するマイグレーションごと削除してしまいたい場合はどうすればいいでしょうか。あまりないことではありますが、できないわけではありません。

まず、ステータスコマンドで削除したいマイグレーションのバージョンを確認します。そして、対象のマイグレーションだけを取り消し、最後にマイグレーションファイルを手動で削除します。

# ステータスを確認
$ rails db:migrate:status

# 対象のマイグレーションを取り消し
$ rails db:migrate:down VERSION=20190814110732

# マイグレーションファイルを削除
$ rm db/migrate/20190812090038_add_picture_to_articles.rb

取り消す前に削除してしまった場合

マイグレーションを取り消す前にマイグレーションファイルを削除してしまい、さらに復元することもできない場合。この状態でステータスを確認すると、以下のようになっているはずです。このような状態だと、マイグレーションファイルがないのでdownにすることもできません。

$ rails db:migrate:status
database: db/development.sqlite3

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190808140406  Create articles
   up     20190810152518  Add category to articles
   up     20190812090038  ********** NO FILE **********

こうなってしまったら、一度ダミーのマイグレーションファイルを作成し、それからマイグレーションを取り消し、マイグレーションファイルを手動で削除します。

# ダミーのマイグレーションファイルを作成
# (重要:タイムスタンプは必ず一致させる)
$ touch db/migrate/20190812090038_dummy.rb

# 適当なマイグレーションを記述する
$ vi /db/migrate/20190812090038_dummy.rb

# マイグレーションを実行
$ rails db:migrate

# 対象のマイグレーションを取り消し
$ rails db:migrate:down VERSION=20190812090038

# マイグレーションファイルを削除
$ rm db/migrate/20190812090038_dummy.rb

ダミーのマイグレーションファイル。

class Dummy < ActiveRecord::Migration
  def change
  end
end

もう一度ステータスを確認するとNO FILEの表示が消えているはずです。

まとめ

トラブルシューティングのセクションでは、私が実際に陥ったトラブルについても書いています。当時はまだRuby on Railsを使い始めたばかりの頃だったので、ちんぷんかんぷんになってとにかく焦ったことを今でも覚えています。マイグレーションの実行周りはとにかくトラブルが起こりやすいので、慎重に行う必要がありますね。

本記事を参考にして、マイグレーションの実行について覚えていただければと思います。

関連記事

【Rails】Railsアップグレードまとめ
# はじめに Ruby on Railsに限らず、何らかのフレームワークを使ってWebシステムを構築している場合、フレームワークのアップグレード作業は避けて通れません。 一般的にフレームワークはバージョン毎にEOL (End of Life [...]
2022年10月1日 14:32
【Rails】ユーザー登録時に行うメールアドレス認証機能の実装方法
# はじめに ユーザー登録/解除やログイン/ログアウトといった認証機能の導入に「devise」というGemを使っている人は多いと思います。「devise」では以下のように記述するだけで、ユーザー登録時に確認メールを送付しメールアドレス認証を行う機 [...]
2022年9月24日 14:24
【Rails】モデルに列挙型(enum)を定義し、使いこなす方法
# はじめに Railsはモデルでカラム名と同名の列挙型(enum)を定義することで、カラムと列挙型の変数を紐付けることができます。カラムと列挙型の変数を紐付けると、カラムに対して様々な便利な使い方ができるようになります。 本記事では、モデ [...]
2022年9月3日 10:29
【Rails】RailsでCORSとPreflight requestの設定を行う方法
# はじめに RailsアプリをAPIサーバーとして構築するには、CORS (Cross-Origin Resource Sharing)と Preflight requestの設定を行う必要があります。APIサーバーは外部からの要求に対して処理 [...]
2022年8月27日 10:44
【Ruby】Bundlerを使ってRubyGemsを作成/公開する方法
# はじめに Bundlerを使ってRubyGemsを作成および公開する方法について説明します。Bundlerを使わずにRubyGemsを作成/公開する方法については以下の記事を参照してください。 <iframe class="hatena [...]
2022年7月12日 23:18
【Ruby】RubyGemsを作成/公開する方法
# はじめに RubyGemsを作成および公開する方法について説明します。Bundlerを使ってRubyGemsを作成する方法については以下の記事を参照してください。 <iframe class="hatenablogcard" style [...]
2022年7月11日 21:52
【Rails】M1チップ搭載MacでRuby on Railsの開発環境構築
# はじめに M1チップ搭載MacにRuby on Railsの開発環境を構築する手順を記載します。 - MacBook Air (M1, 2020) - macOS Monterey 12.3.1 # Homebrew ## [...]
2022年5月5日 11:56
【Rails】Rakeタスクの基本情報と作成・実行方法
# はじめに Railsには標準でRakeというGemが同梱されています。RakeはRubyで実装されたMake(UNIX系のOSで使用できるコマンド)のようなビルド作業を自動化するツールです。Ruby Make、略してRakeというわけですね。 [...]
2022年3月7日 22:12