Yuki Matsumoto

To be engneer soon / Ruby on Rails

マイグレーションでよく出てくるクラスやメソッドについて

2019-03-12 Yuki Matsumoto学習

今回はマイグレーション関連の基礎知識まとめについて書いてみます。

マイグレーションとは

そもそもマイグレーションとはデータベースのスキーマ変更の役割を担うもの。(※スキーマファイルとはマイグレーションファイルの集合です。) railsではマイグレーションの生成時に作成されるタイムスタンプ値(例:201903140739324のような)を使ってそのスクリプトが実行済みかどうかを管理します。

Railsではschema_migrationsテーブルとdb/migrateフォルダ配下のマイグレーションファイルを比較し、未実行のマイグレーションを自動的に認識し実行しています。

マイグレーション機能では特定のタイミングでスキーマの状態を戻したり、指定視されたバージョンだけスキーマをロールバックすることもできる。

メソッドの種類について

マイグレーションファイルではchange, up, downなどのメソッドを使います。このメソッドについて説明します。

changeメソッド

changeメソッドはスキーマ操作の実処理を表す基本です。マイグレーションを自作する場合に使います。このメソッドを使うと、Active Recordがマイグレーションを逆方向に実行(ロールバック)する方法を自動的に理解してくれるので便利な機能です。changeでサポートされているマイグレーション定義は以下。

  • add_column
  • addforeignkey
  • add_index
  • add_reference
  • add_timestamps
  • changecolumndefault (:fromと:toの指定は省略できない)
  • changecolumnnull
  • createjointable
  • create_table
  • disable_extension
  • dropjointable
  • drop_table (ブロックを渡さなければならない)
  • enable_extension
  • remove_column(型を指定しなければならない)
  • removeforeignkey(2番目のテーブルを指定しなければならない)
  • remove_index
  • remove_reference
  • remove_timestamps
  • rename_column
  • rename_index
  • rename_table

up/downメソッド

upメソッドはスキーマに対する変換方法を記述し、downメソッドにはupメソッドによって行われた変換を逆転する方法を記述する必要がある。つまり、upの後にdownを実行した場合、スキーマが変更されないようにする必要がある。例えばupメソッドでテーブルを作成したら、downメソッドでテーブルを削除する必要がある。downメソッド内で行う変換の順序はupメソッドの逆になるようにする。

class ExampleMigration < ActiveRecord::Migration [5.0]
  def up
    create_table :distributors do |t|
      t.string :zipcode
    end
 
    # CHECK制約を追加
    execute <<-SQL
      ALTER TABLE distributors
        ADD CONSTRAINT zipchk
        CHECK (char_length(zipcode) = 5);
    SQL
 
    add_column :users, :home_page_url, :string
    rename_column :users, :email, :email_address
  end
 
  def down
    rename_column :users, :email_address, :email
    remove_column :users, :home_page_url
 
    execute <<-SQL
      ALTER TABLE distributors
        DROP CONSTRAINT zipchk
    SQL
 
    drop_table :distributors
  end
end

参照: Active Record マイグレーション

revertメソッド

revertメソッドはActive Recordのマイグレーションロールバック機能を利用できます。revertメソッドは逆転を行う命令を含むブロックを受け取ることができる。これは、以前のマイグレーションの一部のみを逆転したい場合に便利です。

たとえば、ExampleMigrationがコミット済みになっており、後になって郵便番号を検証するにはCHECK制約よりもActive Recordのバリデーションを使う方がよいことに気付いたとしましょう。revertを使わずに同様のマイグレーションを自作することもできますが、その分余計な手間がかかります (createtableとreversibleの順序を逆にし、createtableをdroptableに置き換え、最後にupとdownを入れ替えます)。 revertはこれらを一手に引き受けてくれます。参照: [Active Record マイグレーション](https://railsguides.jp/activerecord_migrations.html)

class DontUseConstraintForZipcodeValidationMigration < ActiveRecord::Migration[5.0]
  def change
    revert do
      # ExampleMigrationのコードをコピー&ペースト
      reversible do |dir|
        dir.up do
          # CHECK制約を追加
          execute <<-SQL
            ALTER TABLE distributors
              ADD CONSTRAINT zipchk
                CHECK (char_length(zipcode) = 5);
          SQL
        end
        dir.down do
          execute <<-SQL
            ALTER TABLE distributors
              DROP CONSTRAINT zipchk
          SQL
        end
      end
 
      # 以後のマイグレーションはOK
    end
  end
end

マイグレーションの実行について

マイグレーションをすぐに実行する場合はrails db:migrateを打ち込む。これで未実行のchangeまたはupメソッドを実行する。未実行のマイグレーションがない場合は何もせずに終了する。

ロールバック

直前に行ったマイグレーションをロールバックする場合に使う

rails db:migrate

これはchangeメソッドを逆転実行するか、downメソッドを実行する。マイグレーションを複数ロールバックする場合はSTEPパラメータを指定する。

rails db:rollback STEP=3

※ db:migrateで実行できないタスクをこれらのタスクで実行することはできません。これらは単にバージョンを明示的に指定しなくて済むようにdb:migrateタスクを使いやすくしたものに過ぎない。

データベースを設定する

rails db:setupタスクはデータベースの作成、スキーマの読み込み、シードデータを用いてデータベースの初期化を実行する。

データベースをリセットする

rails db:resetタスクはデータベースをdropして再度設定する。ちなみにこれは rails db:drop db:setupと同じ。

まとめ

今回はマイグレーションに関する内容で気になったものをメモってみました。実は今回ブログ書いた背景として友達のエンジニアにも必要な道具(知識)はそろそろ調べてから使ったほうがいいよと言われたのがきっかけです。正直これまでほぼ写経でなんとんかく進めてアプリ動いて「すげー」となってましたが、確かに次のステップに行かないとということで細かい書きました。