マイグレーションでできることのまとめ

マイグレーションとは

SQLを直接使わずに、データベースのテーブルやカラムを変更できる仕組み。 変更の1つ1つをRubyのファイル(マイグレーションファイル)として実現している。

マイグレーション作成コマンド

$ rails generate migration クラス名

クラス名は何でもOKだが、基本は「すること+テーブル名」。 例えばUserテーブルのhogeカラムを変更したい場合は ChangeHogeToUser で、Userテーブルを削除したい場合は DropUser となる。

マイグレーションでできること

マイグレーションを可逆的にする(up, down)

upはマイグレーション実行時に実行され、downはロールバック実行時に実行されるメソッド。 下記のコードでは、マイグレーションを実行するとテーブルが削除され、ロールバックを実行すると元のテーブルが復元される。

class DropUser < ActiveRecord::Migration[5.0]
    # 変更内容
  def up
    drop_table :users
  end

  # 変更前の状態
  def down
    create_table :users do |t|
      t.string :uuid
      t.string :name
      t.timestamps
    end
  end
end
テーブル名の変更

下記のコードではテーブル名をissuesからtasksに変更している。

class RenameIssueToTask < ActiveRecord::Migration
  def change
    rename_table :issues, :tasks
  end
end
既存カラムの変更

下記のコードではUserモデルのuuidカラムをNOT NULL制約に変更している。

class ChangeColumnToUser< ActiveRecord::Migration
  def up
    change_column :users, :uuid, :string, null: false, default: 0
  end

  def down
    change_column :users, :uuid, :string, null: true, default: 0
  end
end
既存カラムを変更する際のオプション

①NULL / NOT NULL

# NULL
change_column :テーブル名, :カラム名, :型, null: true

# NOT NULL
change_column :テーブル名, :カラム名, :型, null: false

②インデックス

特定のカラムからデータを取得する際に、そのカラムのデータを複製して検索を行いやすくするためのもの。例えばUsersテーブルのnameカラムにインデックスを張ることで、アルファベット順にnameを並べ替えて検索しやすくしてくれる(並び替えた後にどういった検索処理が行われるのかはよく分かってない)

change_column :テーブル名, :カラム名, :型, index: true

③デフォルト値

change_column :テーブル名, :カラム名, :型, default: "piyo"

④長さ

change_column :テーブル名, :カラム名, :string, limit: 12

⑤小数部の精度を指定する

change_column :テーブル名, :カラム名, :型, precision: 6
カラム名の変更
class RenameAgeToNenrei < ActiveRecord::Migration
  def change
    rename_column :User, :age, :nenrei
  end
end
カラムを追加/削除する
class AddColumnToUser < ActiveRecord::Migration
  def change

    # 追加
    add_column :users, :piyo, :string

    # 削除
    remove_column :users, :piyo, :string

    # まとめて削除
    remove_columns :users, :column_1, :column_2 [, ...]

    # 追加する場所を指定する場合
    add_column :users, :piyo, :string, :after => :uuid
  end
end
インデックスを追加/削除する

複合ユニークの使い所は、例えばユーザAから投稿Aへのいいねなど。この組み合わせは一意にしておかないと、この例で言うと同じユーザが1つの投稿に何度もいいねできることになる。

class AddIndexToUser < ActiveRecord::Migration
  def change

    # 追加
    add_index :users, :name

    # ユニーク追加
    add_index :users, :name, :unique => true

    # 削除
    remove_index :users, :name

    # 複合インデックスの場合
    add_index :users, [:name, :name2]

    # 複合ユニークの場合
    add_index :user_accounts, [:provider, :uid], :unique => true

  end
end
外部キーを作成/削除する

外部キーとは、テーブル同士の紐づけに用いるカラムのこと。usersテーブルとpostsテーブルがあったとして、このpostはどのuserが投稿したものなんだろう?というのをpostsテーブルで確認したい時に、user_idのカラムを用いる。user_idはusersテーブルでは主キーと呼ばれる。

class CreateUserAccounts < ActiveRecord::Migration[5.0]
  def change
    create_table :user_accounts do |t|
      t.references :user,  index: true, foreign_key: true

      t.timestamps
    end
  end
end

モデル作成時に作成する場合 $ rails g model UserAccount user:references

class AddRefUser < ActiveRecord::Migration
  def change
    add_reference :users, :article, foreign_key: true

    # 外部キーの削除はこちら
    remove_foreign_key :users, column: :article_id

    # カラムも一緒に削除する場合はこちら
    remove_reference :users, :article, foreign_key: true
  end
end

既存のテーブルに追加する場合 $ rails g migration AddArticleToUsers article:references

ポリモーフィックを作る

ポリモーフィックとは、複数の異なる型やオブジェクトに対して共通のインタフェース(Rubyの世界でならメソッドと言い換えてもよさそう)を提供すること。すごく単純化して言うと、同じ名前のメソッドがそれぞれ異なるクラスで規定されていること。もちろんそのメソッドの内容はそれぞれ異なる。ダックタイピングの一種。

class CreateMessages < ActiveRecord::Migration[5.0]
  def change
    create_table :messages do |t|
      t.references :messagable, polymorphic: true
      t.text :message

      t.timestamps
    end
  end
end

モデル作成時に作成する場合:$ rails g model message messagable:references{polymorphic} message:text

実際にポリモーフィックを利用したコードは例えば以下のような感じ。 EmployerとEmployee、どちらもsender_nameという同じ名前のメソッドを所有しているが、 どちらのsender_nameを使う際もコードはMessage.find(params[:id]).messageable.sender_nameとなる。

class Message < ApplicationRecord
  belongs_to :messageable, polymorphic: true
end

class Employer < ApplicationRecord
  has_many :messages, as: :messageable

    # 共通のインターフェース
  def sender_name
    company_name
  end
end

class Employee < ApplicationRecord
  has_many :messages, as: :messageable

    # 共通のインターフェース
  def sender_name
    "#{last_name} #{first_name}"
  end
end

参考

rails generate migrationコマンドまとめ - Qiita

Railsのポリモーフィック関連とはなんなのか - Qiita