【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】Paranoiaを使用した論理削除(ソフトデリート)
# はじめに Paranoiaは、Railsアプリケーションで論理削除(ソフトデリート)を実現するためのGemです。 論理削除は、データベースのレコードを物理的に削除するのではなく、削除フラグを設定することで「削除済み」とみなす方法です。こ [...]
2024年7月20日 21:33
【Rails】activerecord-multi-tenantを使用したマルチテナントアプリケーションの作成
# はじめに マルチテナントアプリケーションでは、複数の顧客(テナント)が同じアプリケーションを利用するため、データの分離が必要です。 activerecord-multi-tenantは、このようなマルチテナント環境をサポートするための便 [...]
2024年7月18日 16:50
【Rails】RubyとRailsにおけるattr_reader, attr_writer, attr_accessorの概念と使用方法
# はじめに RubyとRailsの開発において、`attr_reader`,`attr_writer`,`attr_accessor`は非常に便利なメソッドです。これらは、クラス内でインスタンス変数に対するゲッターおよびセッターメソッドを簡単に [...]
2024年7月17日 18:11
【Rails】RubyとRailsにおけるyieldの概念と使用方法
# はじめに RubyとRailsにおける`yield`は、メソッドやテンプレートの中で動的にコードブロックを実行する能力を提供し、これによってコードの再利用性と拡張性が大幅に向上します。本記事では、RubyとRailsにおける`yield`の概 [...]
2024年7月17日 13:15
【Rails】AASMを使用してオブジェクトの状態遷移を効率的に管理
# はじめに Railsアプリケーションにおいて、オブジェクトの状態管理は重要な課題の一つです。AASM (Acts As State Machine) gemは、複雑な状態遷移を効率的に管理します。本記事では、AASMの基本的な使い方を解説して [...]
2024年7月16日 18:00
【Rails】RSpec + Swagger + rswagでアプリケーションのAPIをテストおよびドキュメント化する方法
# はじめに Railsアプリケーションの開発において、APIのテストとドキュメント化は重要な要素です。 RSpecはテストフレームワークとして広く利用されており、SwaggerはAPIの設計とドキュメント化を支援します。これらを統合するr [...]
2024年7月16日 14:27
【Rails】mailcatcherを使用して開発環境でメール送信をテストする方法
# はじめに mailcatcherは、開発環境でのメール送信をキャプチャするためのツールです。ローカルで送信されたメールをブラウザ上で簡単に確認できるようにします。mailcatcherをRailsアプリケーションで使用する方法について説明しま [...]
2024年7月15日 16:37
【Rails】impressionistを使用してページビューやクリック数を追跡する方法
# はじめに impressionist Gemを使用してRailsアプリケーションでページビューやクリック数を追跡する方法について説明します。 # 実装方法 ## impressionist Gemのインストール まず、impre [...]
2024年7月15日 14:18