【Rails】マイグレーションファイルを徹底解説!

Rails

マイグレーションファイルとは

データベースの設計図です。
このファイルを実行することにより記述した内容がデータベースに反映されます。

railsでデータベースに対して何らかの変更を行いたい場合、全てマイグレーションファイルというファイルを作成・編集して読み込ませることによりテーブルを作成したり、カラムを追加したりします。

マイグレーションファイルの実行の仕方
リンクをコピーしました

作成・編集したマイグレーションファイルはターミナルで下記のコマンドを実行すると読み込まれ、データベースに反映されます。

shell
1
$ rails db:migrate

rails db:migrateコマンド
リンクをコピーしました

マイグレーションファイルを実行し、データベースに反映させるためのコマンドです。
※ rails4までは「rake」コマンド

schema_migrationsテーブル
リンクをコピーしました

schema_migrationsテーブルはmigrateが実行されると自動でデータベースに作成されるテーブルです。

このテーブルには実行されたマイグレーションファイルのバージョンが保存されていきます。

マイグレーションファイルは「20XXXXXXXXXXXX_hoge_hoge.rb」のような名前で作成されます。

「20XXXXXXXXXXXX」の部分には日時の情報が自動的に入り、この部分がバージョンを表します。

schema_migrationsテーブル

migrationが成功するとそのmigrationファイルのversionがschema_migrationsテーブルに保存されます。
またmigrateが成功したら増えていきます。

マイグレーションファイルの状態を確認しよう
リンクをコピーしました

マイグレーションファイルがたくさん作成されると現在どこまでのマイグレーションファイルがschema_migrationsテーブルに保存されているか確認したいときがあります。

直接データベースを視覚化できるアプリで確認することもできるのですが、この状態をターミナルに出力できるコマンドがあります。

それが下記のコマンドです。

shell
1
$ rails db:migrate:status

このコマンドを実行すると現在のマイグレーションファイルの状態を調べることができます。

shell
1
2
3
4
5
6
7
8
 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20XXXXXXXXXXX  マイグレーション名
   up     20XXXXXXXXXXX  マイグレーション名
   up     20XXXXXXXXXXX  マイグレーション名
   up     20XXXXXXXXXXX  マイグレーション名
   up     20XXXXXXXXXXX  マイグレーション名
   up     20XXXXXXXXXXX  マイグレーション名

schema_migrationsテーブルにversionがあればup、versionがなければdownと表示されます。

upになっているマイグレーションファイルはすでに実行済みのファイルなので「rails db:migrate」コマンドを入力しても読み込まれることはありません。

なのでもし間違った名前でカラムを作成してしまったときにupになっているマイグレーションファイルを編集しても、読み込まれないので意味がないことになります。

それではそういう時はどうしたら良いのでしょう

rails db:rollbackコマンド
リンクをコピーしました

このコマンドを実行することにより最新のマイグレーションファイルのバージョンが schema_migrationsテーブルから削除されます。

つまりがupからdownになり、データベースがmigrateされる前の状態に戻ります。
もう一度実行すると次に新しいマイグレーションファイルがdown状態になります。
同時に複数のマイグレーションファイルをrollbackさせたい時は下記のように記述します。

shell
1
2
# 3つのマイグレーションファイルをロールバックしたい時
$ rails db:rollback STEP=3

上のコマンドを入力した後の状態は下記のようになります。

shell
1
2
3
4
5
6
7
8
 Status   Migration ID    Migration Name
--------------------------------------------------
     up        20XXXXXXXXXXX  マイグレーション名
     up        20XXXXXXXXXXX  マイグレーション名
     up        20XXXXXXXXXXX  マイグレーション名
   down     20XXXXXXXXXXX  マイグレーション名
   down     20XXXXXXXXXXX  マイグレーション名
   down     20XXXXXXXXXXX  マイグレーション名

down状態になったマイグレーションファイルは「rails db:migrate」コマンドを実行した際、読み込まれてデータベースに反映されるので、もし間違ってカラム名をつけてしまった時は「rails db:rollback」コマンドでupからdownにした後にマイグレーションファイルを修正し、再度「rails db:migrate」コマンドを実行するという流れになります。

マイグレーションファイルを削除する際の注意点
リンクをコピーしました

マイグレーションファイルはいわばデータベースを作成した歴史です。

ですので実行されてup状態になっているマイグレーションファイルは絶対に削除したり編集したりしてはいけません。

もし誤ってup状態のマイグレーションファイルを削除してしまった状態でアプリをサーバーにアップした時、エラーが出てしまうためです。

サーバーにアップされたマイグレーションファイルは最初は全てdown状態になっています。

それを「rails db:migrate」コマンドで実行するのですが、例えばusersテーブルを作成するマイグレーションファイルを削除してしまって、その後にusersテーブルにカラムを追加するマイグレーションファイルがあった時どうなるでしょう?

そうですね、存在しないusersテーブルにカラムを追加することはできないのでエラーが出てしまいます。

ローカルだとすでにusersテーブルは削除してしまったマイグレーションファイルによって作成されているため、エラーが出なかったわけです。

このようなことが起こりえるため、マイグレーションファイルを削除する際は必ずdown状態になっているのを確認してから削除するようにしましょう。

間違って削除してしまったら
リンクをコピーしました

間違ってマイグレーションファイルを削除してしまうと「rails db:migrate:status」コマンドでマイグレーションファイルの状態を確認すると下記のように「NO FILE」と表示されます。

shell
1
2
3
4
5
6
 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190429100951  Create tweets
   up     20190510075537  Add name to tweets
   up     20190510085623  ********** NO FILE **********
   up     20190511025036  Add email to users

「NO FILE」と表示されるのはschema_migrationsテーブルにバージョンが保存されているためです。

ですので、schema_migrationsテーブルから削除してしまったマイグレーションファイルのバージョンが保存されているレコードを削除すればこの表示は消えます。

schema_migrationsテーブル

shell
1
2
3
4
5
 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190429100951  Create tweets
   up     20190510075537  Add name to tweets
   up     20190511025036  Add email to users

すると「NO FILE」という表示が消えました。
これでschema_migrationsとの齟齬がなくなりましたが、前述した通りサーバーにアップする際にエラーが出るので、しっかりと修正をしておきましょう。

スキーマファイル
リンクをコピーしました

マイグレーションが実行されると「db」フォルダにschema.rbというファイルが作成されます。
これがスキーマファイルです。

スキーマファイルにはschema_migrationsテーブルの最後のレコードのversionが記録されます。

ruby
1
2
3
4
5
6
7
8
9
10
ActiveRecord::Schema.define(version: 20XX_XX_XX_XXXXXX) do

  create_table "hoges", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
    t.string "name"
    t.text "body"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

end

一番上の行のかっこ内「version」の部分がマイグレーションファイルのバージョンを表しています。

このファイルを見ればどのマイグレーションファイルまでが実行済みなのかや、現在のデータベースの構造を確認することができます。

これを各テーブルごとにコピーして各モデルファイルにコメントアウトをして保存しておくと便利です。

マイグレーションファイルの作成方法
リンクをコピーしました

下記のコマンドによりモデルを作成するとモデルファイルと一緒にマイグレーションファイルが作成されます。

shell
1
$ rails g model モデル名

作成されたマイグレーションファイルはdb/migrateフォルダ内に入っています。

この最初に作成されたマイグレーションファイルを編集してテーブルを作成するのが一般的です。

その後、作成したテーブルに変更を加えたりするときはすでにあるマイグレーションファイルを編集するのではなく、新たに別のマイグレーションファイルを作成して変更をするコードを記述します。

その際の新しいマイグレーションファイルを作成するコマンドは下記の通りです。

shell
1
$ rails g migration マイグレーション名

マイグレーションファイルの編集の仕方
リンクをコピーしました

モデルファイルと一緒に作成されたマイグレーションファイルは下記のコードが書かれた状態で作成されます。

ruby
1
2
3
4
5
6
7
8
class CreateHoges < ActiveRecord::Migration[5.2]
  def change
    create_table :hoges do |t|

      t.timestamps
    end
  end
end

2行目のchangeというメソッドの中にcreate_tableという記述があります。
その次に:hogesとあるのはテーブル名です。
この記述によりマイグレーションファイルが実行されるとhogesテーブルがデータベースに作成されます。

テーブルの中にカラムを作成しよう
リンクをコピーしました

上のままのコードだとテーブルの中にはレコードが作成された日時を保存するためのcreated_atというカラムとレコードが上書きされた日時を保存するためのupdated_atと言うカラムしか作成されません。

※「t.timestamps」の記述により作成されます

カラムを作成するにはマイグレーションファイル内に下記の記述をします。

ruby
1
2
3
4
5
6
7
8
class CreateHoges < ActiveRecord::Migration[5.2]
  def change
    create_table :hoges do |t|
      t.カラムの型  :カラム名
      t.timestamps
    end
  end
end

テーブルの型を定義しよう
リンクをコピーしました

カラムの型というのはどういう状態でデータを保存するかという指定です。
文字として保存するのか数値として保存するのかといったような指定をすることができます。

カラムに指定できる型は下記のようなものがあります。

説明 用途
string 文字(255文字まで) 名前やメールアドレスなど短い文字
text 長い文章 ブログの記事や投稿される内容
integer 整数(4byte) 通常使用する範囲の整数で保存したいとき
smallint 整数(2byte) 狭範囲の整数で保存するとき
bigint 整数(8byte) かなり大きな整数で保存する可能性があるとき
float 浮動小数点数 小数点を含めた数値を保存したいとき
decimalnumeric 固定長整数 桁の大きな数を桁数などを指定して保存したいとき※2つの違いはほぼなし
boolean 真か偽か trueかfalseで保存したいとき
time 時刻型 時刻を「12:00:00」の形で保存したいとき
date 日付型 日付を「2001-01-01」の形で保存したいとき
datetime 日時型 日時を「2001-01-01 01:01:00」の形で保存したいとき
json json型 JSONとして保存したいとき
binary バイナリ文字列型 画像ファイルなどバイナリデータとして保存したいとき
references 外部キーの定義 外部キーを追加したいとき

それでは各型の詳細をみていきましょう。

string型
リンクをコピーしました

255文字までの文字を保存したいときに指定します。
名前やemailアドレスなど普通に考えて255文字以上にならないときはstring型を使いましょう。

text型
リンクをコピーしました

255文字以上になることが予想されるときに指定します。
string型より読み込む際時間がかかるので、明らかに255文字以内で収まることが予想できるのであればstring型を使いましょう。

integer型
リンクをコピーしました

整数として保存したいときに指定します。
-2,147,483,648から+2,147,483,647の整数を保存できます。
基本的に整数として保存したい場合はinteger型にしておくのが良いでしょう。

smallint型
リンクをコピーしました

狭範囲の整数で保存するときに指定します。
-32,768から+32,767の整数を保存できます。

bigint型
リンクをコピーしました

かなり大きな整数を保存する可能性があるときに指定します。
-9,223,372,036,854,775,808から+9,223,372,036,854,775,807の整数を保存できます。

float型
リンクをコピーしました

小数点を含めた数値として保存したいときに指定します。
身長や体重など小数点も含めた数値で保存したいときはこちらで指定しましょう。

decimal型、numeric型
リンクをコピーしました

decimal、numericで指定するとオプションとしてprecision(全体の桁数)とscale(小数点以下の桁数)をつけることができます。

ruby
1
2
#10桁の数字と小数点5までの数字を保存するように指定
t.decimal :hoge,  precision: 10, scale: 5

なお小数点前までは131,072桁まで、小数点以降は16,383桁まで設定できます。

boolean型
リンクをコピーしました

trueかflase、つまり2択で保存したいときに指定します。
例えばtodoアプリで実行されたタスクはtrueで、まだ実行されていないタスクはfalseで保存するといったようなときに使います。

boolean型で指定するときはdefaultの値をセットしておくのが良いです。

ruby
1
2
#hogeカラムをdefaultの値がfalseでboolean型で定義
t.boolean  :hoge, default: false

time型
リンクをコピーしました

時刻を保存するときに指定します。
「12:00:00」の形で保存されます。

date型
リンクをコピーしました

日付を保存したいときに指定します。
「2001-01-01」の形で保存されます。

datetime型
リンクをコピーしました

日時を保存したいときに指定します。
「2001-01-01 01:01:00」の形で保存されます。

json型
リンクをコピーしました

JSON形式で保存したいときに指定します。

binary型
リンクをコピーしました

画像ファイルや動画ファイルを保存したいときに指定します。

references型
リンクをコピーしました

外部キーを追加するときに指定します。
例えば「t.references :user」と指定すると「user_id」というカラムが追加されます。
ただしこれだけでは外部キー制約がつかないので下記のように記述します。

ruby
1
t.references :user, foreign_key: true

書き方の例
リンクをコピーしました

名前を保存するためのnameカラムと、投稿文を保存するtextカラムをtweetsテーブルに作成したいとします。

マイグレーションファイルには型も指定しなければいけないので、どのような型で作成するかを考える必要があります。

どの型がベストか考えてみよう
リンクをコピーしました

nameカラムは名前を保存します。
名前は文字として保存するのでstring型かtext型になります。
ただ名前はどう考えても255文字以上になることはないのでstring型がいいですよね。

textカラムも文字として保存しますが、255文字以上になることも考えられるのでtext型で作成することにします。

このように保存するデータがどういったものかを考え、最適な型を指定することが大事です。

今回のマイグレーションファイルの記述は下記のようなコードになります。

ruby
1
2
3
4
5
6
7
8
9
class CreateHoges < ActiveRecord::Migration[5.2]
  def change
    create_table :hoges do |t|
      t.string  :name
      t.text     :text
      t.timestamps
    end
  end
end

今回はモデルを作成した際に作られるマイグレーションファイルに対する記述でした。
では今作成したhogesテーブルに新たにカラムを追加したい場合はどうすれば良いでしょう?

データベースを編集したい場合は全てマイグレーションファイルから行います。
ですので新たにマイグレーションファイルを作成する必要があります。

新たに作成したマイグレーションファイルを編集してみよう
リンクをコピーしました

新たなマイグレーションファイルを作成するには下記のコマンドを実行するのでした。

shell
1
$ rails g migration マイグレーション 名

作成されたマイグレーションファイルの初期状態はこんな感じになっています。

ruby
1
2
3
4
class マイグレーション名 < ActiveRecord::Migration[5.2]
  def change
  end
end

この時のhogesテーブルに「name」というカラムを「string型」で追加したい場合はadd_columnメソッドを使用します。

ruby
1
2
3
4
5
class マイグレーション名 < ActiveRecord::Migration[5.2]
  def change
      add_column :hoges, :name, :string
  end
end

複数のカラムを追加するときには複数行で記述します。

ruby
1
2
3
4
5
6
class マイグレーション名 < ActiveRecord::Migration[5.2]
  def change
      add_column :hoges, :name, :string
      add_column :hoges, :body, :text
  end
end

このようにテーブルにカラムを追加するときにはadd_columnメソッドを使います。
そのほかに変更を与えるメソッドを確認しておきましょう。

メソッド 用途
add_column カラムを追加する
remove_column カラムを削除する
remove_columns 複数のカラムを削除する
rename_column カラムの名前を変更する
change_column カラムの情報を変更する
create_table テーブルを作成する
drop_table テーブルを削除する
rename_table テーブル名を変更する
add_index インデックスを追加する
remove_index インデックスを削除する
add_reference 外部キーを作成する
remove_foreign_key 外部キーを削除する

詳しい記述方法を確認してみましょう。

add_column
リンクをコピーしました

テーブルにカラムを追加するときに使います。

ruby
1
add_column  :テーブル名, :カラム名, :

remove_column
リンクをコピーしました

テーブルからカラムを削除するときに使います。

ruby
1
remove_column  :テーブル名, :カラム名, :

remove_columns
リンクをコピーしました

複数のカラムをまとめて削除するときに使います。

ruby
1
remove_columns :テーブル名, :カラム名, :カラム名,  :カラム名  [, ...]

rename_column
リンクをコピーしました

カラム名を変更したいときに使います。

ruby
1
rename_column :テーブル名, :変更前のカラム名, :変更後のカラム名

change_column
リンクをコピーしました

追加したカラムの情報を編集したいときに使います。

ruby
1
2
3
4
5
6
7
change_column :テーブル名, :カラム名, :

#(例)usersテーブルのnameカラムの文字数を80文字までに変更させる
change_column  :users, :name, :string, limit: 80

#(例)usersテーブルのnameカラムにNOT NULL制約をつける
change_column :users, :name, :string, null: false

上の例のように後からNOT NULL制約をつけるときなどに使います。

create_table
リンクをコピーしました

新たにテーブルを作成するときに使います。
「rails g model モデル名」コマンドでモデルを作成した際に同時に作られるマイグレーションファイルにあらかじめ記述されているため、自分で書くことはあまりありません。

ruby
1
create_table :テーブル名

drop_table
リンクをコピーしました

作成したテーブルを削除するときに使います。

ruby
1
drop_table  :削除したいテーブル名

rename_table
リンクをコピーしました

作成したテーブルの名前を変更したいときに使います。

ruby
1
rename_table  :現在のテーブル名,  :新しいテーブル名

add_index
リンクをコピーしました

指定したテーブルの指定したカラムにインデックスを付与するときに使います。

ruby
1
add_index  :テーブル名,  :インデックスを付与するカラム名 [, オプション])

remove_index
リンクをコピーしました

付与してあるインデックスを削除するときに使います。

ruby
1
remove_index :テーブル名, :カラム名

add_reference
リンクをコピーしました

外部キーを作成するときに使います。
「foreign_key: true」をつけると外部キー制約もつけることができます。

ruby
1
2
3
4
add_reference  :テーブル名,  :リファレンス名 [, オプション]), foreign_key: true

# (例)hogesテーブルにuser_idというカラムを作成し、user.idに対して外部キー制約をつける
add_reference  :hoges,  :user,  foreign_key: true

remove_foreign_key
リンクをコピーしました

外部キーを削除するときに使います。

ruby
1
remove_foreign_key  :テーブル名,  :リファレンス名

あらかじめコードが書かれている状態で作成してみよう
リンクをコピーしました

カラムを追加したりする際には上記のようにコードを記述するのですが、実はマイグレーションファイルを作成する際のマイグレーション名は何でも構いません。

ですがマイグレーション名を下記のようにとあるパターンの通りに記述すると作成されたマイグレーションファイルにコードが書かれた状態で作成することができます。

例えばカラムを追加する際のマイグレーションファイルを作成する際のマイグレーション名は下記のように記述します。

shell
1
$ rails g migration Add追加するカラム名To追加するテーブル名 追加するカラム名:型

スペースを入れない代わりに先頭の文字を大文字にするのがポイントです。
ではusersテーブルにstring型でnameというカラムを追加するマイグレーションファイルを作成してみましょう。

shell
1
$ rails g migration AddNameToUsers name:string

このコマンドで作成したマイグレーションファイルを開くと下記のような状態で作成されます。

ruby
1
2
3
4
5
class AddNameToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :name, :string
  end
end

逆に今作成したnameカラムをusersテーブルから削除するマイグレーションファイルを作成するときは下記のようなコードを入力します。

shell
1
$ rails g migration RemoveNameFromUsers name:string

このコマンドで作成したマイグレーションファイルを開くと下記のような状態で作成されます。

ruby
1
2
3
4
5
class RemoveNameFromUsers < ActiveRecord::Migration[5.2]
  def change
    remove_column :users, :name, :string
  end
end

マイグレーション名のパターン
リンクをコピーしました

上の例のようにパターンに則ってマイグレーション名を指定するとコードが書かれた状態でファイルを作成できます。

マイグレーション名のパターンは下記の通りです。

マイグレーションファイル名 作成されるマイグレーションファイル
Addカラム名Toテーブル名 add_column
Removeカラム名Fromテーブル名 remove_column
Createテーブル名 create_table

パターンがあるものはパターン通りに作成するのが良いでしょう。

マイグレーションファイルを作成する際の注意点
リンクをコピーしました

上のパターンが定義されていないマイグレーションファイルを作成するときも変更内容がわかるような名前をつけることが大事です。

特に規則はないですが、誰がみてもわかりやすい名前をつけましょう。

ruby
1
2
# カラム名を変更する時の例
RenameFrom変更前のカラム名To変更後のカラム名Onテーブル名

またマイグレーション名は同じ名前で作成することはできません。

shell
1
2
   invoke  active_record
   identical    db/migrate/20XXXXXXXXXXXX_add_name_to_users.rb

このようなエラーが出てしまうので、マイグレーション名は被らないようにしましょう。

可逆的なマイグレーションファイルを作成しよう
リンクをコピーしました

マイグレーションファイルが不可逆的だとrailsはうまくロールバックできません。
不可逆的というのは逆方向に戻す方法がわからないことを言います。

例として下記のマイグレーションファイルをみてみましょう。
このマイグレーションファイルを実行後ロールバックするとどうなるでしょう?

ruby
1
2
3
4
5
6
class マイグレーション名 < ActiveRecord::Migration[5.2]
  def change
      # text型からstring型へ変更
      change_column :hoges, :name, :string
  end
end

実行はもちろんうまくいきます。
ですがロールバックする前はtext型であったという情報が書かれていません。
なのでrailsは前の状態に戻す方法がわからないためエラーとなります。
こういうときには下記のように記述をしておきます。

ruby
1
2
3
4
5
6
7
8
9
10
11
class マイグレーション名 < ActiveRecord::Migration[5.2]
  def up
      # text型からstring型へ変更
      change_column :hoges, :name, :string
  end

  def down
      # string型からtext型へ戻す
      change_column :hoges, :name, :text
  end
end

マイグレーション実行時はupメソッドが実行され、ロールバック時にはdownメソッドが実行されます。

こう書いておけばロールバックする前の型が書かれているので、その通り元に戻すことができます。

何かを追加したりする際はupメソッドで「add_hogehoge」、downメソッドで「remove_hogehoge」となるので、その際はchangeメソッドを使って「add_hogehoge」とまとめて記述することができます。

うまくいかない時は
リンクをコピーしました

このようにデータベースの中にテーブルを作成する際はマイグレーションファイルを使用して作成します。

マイグレーションファイルがたくさんできるとこんがらがってきてうまく実行できない場合も出てきます。

そんな時は一度「rails db:migrate:status」コマンドを使って現在のマイグレーションファイルの状態を確認してみましょう。

up状態のファイルは編集・削除しないよう慎重に編集してみてください。

まとめ

マイグレーションファイルはデータベースの設計図のようなものです。