更新日:
【Rails】 マイグレーションファイルを徹底解説!
マイグレーションファイルとは、データベースの設計図です。このファイルを実行することにより記述した内容がデータベースに反映されます。
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
railsでデータベースに対して何らかの変更を行いたい場合、全てマイグレーションファイルというファイルを作成・編集して読み込ませることによりテーブルを作成したり、カラムを追加したりします。
マイグレーションファイル
この章では、マイグレーションファイルの作成や編集、カラムの型などについて解説します。
マイグレーションファイルの実行の仕方
作成・編集したマイグレーションファイルはターミナルで下記のコマンドを実行すると読み込まれ、データベースに反映されます。
1
$ rails db:migrate
rails db:migrateコマンド
マイグレーションファイルを実行し、データベースに反映させるためのコマンドです。
※ rails4までは「rake」コマンド
schema_migrationsテーブル
schema_migrationsテーブル
はmigrateが実行されると自動でデータベースに作成されるテーブルです。
このテーブルには実行されたマイグレーションファイルのバージョンが保存されていきます。
マイグレーションファイルは20XXXXXXXXXXXX_hoge_hoge.rb
のような名前で作成されます。
20XXXXXXXXXXXX
の部分には日時の情報が自動的に入り、この部分がバージョンを表します。
migrationが成功するとそのmigrationファイルのversionがschema_migrationsテーブルに保存されます。
またmigrateが成功したら増えていきます。
マイグレーションファイルの状態を確認しよう
マイグレーションファイルがたくさん作成されると現在どこまでのマイグレーションファイルがschema_migrationsテーブルに保存されているか確認したいときがあります。
直接データベースを視覚化できるアプリで確認することもできるのですが、この状態をターミナルに出力できるコマンドがあります。
それが下記のコマンドです。
1
$ rails db:migrate:status
このコマンドを実行すると現在のマイグレーションファイルの状態を調べることができます。
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させたい時は下記のように記述します。
1
2
# 3つのマイグレーションファイルをロールバックしたい時
$ rails db:rollback STEP=3
上のコマンドを入力した後の状態は下記のようになります。
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
と表示されます。
1
2
3
4
5
6
Status Migration ID Migration Name
--------------------------------------------------
up 20190429100951 Create tweets
up 20190510075537 Add name to tweets
up 20190511025631 ********** NO FILE **********
up 20190511025645 Add email to users
NO FILE
と表示されるのはschema_migrationsテーブルにバージョンが保存されているためです。
ですので、schema_migrationsテーブルから削除してしまったマイグレーションファイルのバージョンが保存されているレコードを削除すればこの表示は消えます。
1
2
3
4
5
Status Migration ID Migration Name
--------------------------------------------------
up 20190429100951 Create tweets
up 20190510075537 Add name to tweets
up 20190511025645 Add email to users
するとNO FILE
という表示が消えました。
これでschema_migrationsとの齟齬がなくなりましたが、前述した通りサーバーにアップする際にエラーが出るので、しっかりと修正をしておきましょう。
スキーマファイル
マイグレーションが実行されるとdbフォルダ
にschema.rb
というファイルが作成されます。
これがスキーマファイルです。
スキーマファイルにはschema_migrationsテーブルの最後のレコードのversionが記録されます。
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
の部分がマイグレーションファイルのバージョンを表しています。
このファイルを見ればどのマイグレーションファイルまでが実行済みなのかや、現在のデータベースの構造を確認することができます。
これを各テーブルごとにコピーして各モデルファイルにコメントアウトをして保存しておくと便利です。スキーマファイルの取り扱いについては、こちらの参考書で詳しく解説されています。
マイグレーションファイルの作成方法
下記のコマンドによりモデルを作成するとモデルファイルと一緒にこのモデルが担当するテーブルを作成するためのマイグレーションファイルが自動で作成されます。
1
$ rails g model モデル名
作成されたマイグレーションファイルはdb/migrateフォルダ内
に入っています。
この最初に作成されたマイグレーションファイルを編集してテーブルを作成するのが一般的です。
その後、作成したテーブルに変更を加えたりするときはすでにあるマイグレーションファイルを編集するのではなく、新たに別のマイグレーションファイルを作成して変更をするコードを記述します。
その際の新しいマイグレーションファイルを作成するコマンドは下記の通りです。
マイグレーション名は何でも構いませんが、同じ名前で作成することはできません。
1
$ rails g migration マイグレーション名
マイグレーションファイルの編集の仕方
モデルファイルと一緒に作成されたマイグレーションファイルは下記のコードが書かれた状態で作成されます。
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」の記述により作成されます
カラムを作成するにはマイグレーションファイル内に下記の記述をします。
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 | 浮動小数点数 | 小数点を含めた数値を保存したいとき |
decimal numeric |
固定長整数 | 桁の大きな数を桁数などを指定して保存したいとき ※decimal型とnumeric型の違いはほぼなし |
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
(小数点以下の桁数)をつけることができます。
1
2
#10桁の数字と小数点5までの数字を保存するように指定
t.decimal :hoge, precision: 10, scale: 5
なお小数点前までは131,072桁まで、小数点以降は16,383桁まで設定できます。
boolean型
true
かflase
、つまり2択で保存したいときに指定します。
例えばtodoアプリで実行されたタスクはtrue
で、まだ実行されていないタスクはfalse
で保存するといったようなときに使います。
boolean型で指定するときはdefaultの値をセットしておくのが良いです。
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
というカラムが追加されます。
ただしこれだけでは外部キー制約がつかないので下記のようにforeign_key: true
を記述します。
1
t.references :user, foreign_key: true
integer型で外部キーを追加した場合、foreign_key: true
を付けても外部キー制約はつかないので注意しましょう。
1
2
# 下のように記述しても外部キー制約はつかない
t.integer :user_id, foreign_key: true
その際は後述するadd_foreign_keyメソッドを使い、定義します。
書き方の例
名前を保存するためのnameカラムと、投稿文を保存するtextカラムをtweetsテーブルに作成したいとします。
マイグレーションファイルには型も指定しなければいけないので、どのような型で作成するかを考える必要があります。
どの型がベストか考えてみよう
nameカラムは名前を保存します。
名前は文字として保存するのでstring型かtext型になります。
ただ名前はどう考えても255文字以上になることはないのでstring型がいいですよね。
textカラムも文字として保存しますが、255文字以上になることも考えられるのでtext型で作成することにします。
このように保存するデータがどういったものかを考え、最適な型を指定することが大事です。
今回のマイグレーションファイルの記述は下記のようなコードになります。
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テーブルに新たにカラムを追加したい場合はどうすれば良いでしょう?
データベースを編集したい場合は全てマイグレーションファイルから行います。
ですので新たにマイグレーションファイルを作成する必要があります。
新たに作成したマイグレーションファイルを編集してみよう
新たなマイグレーションファイルを作成するには下記のコマンドを実行するのでした。
1
$ rails g migration マイグレーション名
作成されたマイグレーションファイルの初期状態はこんな感じになっています。
1
2
3
4
class マイグレーション名 < ActiveRecord::Migration[5.2]
def change
end
end
この時のhogesテーブルにname
というカラムをstring型
で追加したい場合はadd_columnメソッドを使用します。
1
2
3
4
5
class マイグレーション名 < ActiveRecord::Migration[5.2]
def change
add_column :hoges, :name, :string
end
end
複数のカラムを追加するときには複数行で記述します。
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_reference | 外部キーを削除する |
add_foreign_key | 外部キー制約を作成する |
remove_foreign_key | 外部キー制約を削除する |
詳しい記述方法を確認してみましょう。
add_column
テーブルにカラムを追加するときに使います。
1
add_column :テーブル名, :カラム名, :型
remove_column
テーブルからカラムを削除するときに使います。
1
remove_column :テーブル名, :カラム名, :型
remove_columns
複数のカラムをまとめて削除するときに使います。
1
remove_columns :テーブル名, :カラム名, :カラム名, :カラム名
rename_column
カラム名を変更したいときに使います。
1
rename_column :テーブル名, :変更前のカラム名, :変更後のカラム名
change_column
追加したカラムの情報を編集したいときに使います。
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 モデル名
コマンドでモデルを作成した際に同時に作られるマイグレーションファイルにあらかじめ記述されているため、自分で書くことはあまりありません。
1
create_table :テーブル名
drop_table
作成したテーブルを削除するときに使います。
1
drop_table :削除したいテーブル名
rename_table
作成したテーブルの名前を変更したいときに使います。
1
rename_table :現在のテーブル名, :新しいテーブル名
add_index
指定したテーブルの指定したカラムにインデックスを付与するときに使います。
インデックスを設定するとデータを検索するときの速度を高速化することができます。
1
add_index :テーブル名, :インデックスを付与するカラム名 [, オプション])
remove_index
付与してあるインデックスを削除するときに使います。
1
remove_index :テーブル名, :カラム名
add_reference
外部キーを作成するときに使います。
1
2
3
4
add_reference :テーブル名, :リファレンス名 [, オプション]
# (例)hogesテーブルに外部キーであるuser_idカラムを作成
add_reference :hoges, :user
このとき、オプションでforeign_key: true
をつけると外部キー制約をつけることができます。
1
2
# (例)hogesテーブルに外部キーであるuser_idカラムを作成し外部キー制約を付ける
add_reference :hoges, :user, foreign_key: true
add_referenceメソッド
はこのように外部キーを作成するメソッドです。
ですので、foreign_key: true
をつけないで外部キーを作成した後に外部キー制約をつけようと新たなマイグレーションファイル で下記のコードを実行すると外部キーはすでに作成されているためエラーが発生します。
1
2
# user_idカラムはすでに存在しているのでエラーが発生する
add_reference :hoges, :user, foreign_key: true
外部キーを作成後に新たなマイグレーションファイルで外部キー制約をつけたい場合は後述するremove_foreign_keyメソッド
を使います。
※外部キーや外部キー制約については図解形式で理解する《アソシエーション解説書》の記事を参照してください
remove_reference
外部キーを削除するときに使います。
1
2
3
4
remove_reference :テーブル名, :リファレンス名
# (例)hogesテーブルの外部キーであるuser_idカラムを削除
add_reference :hoges, :user
add_foreign_key
外部キー制約を作成するときに使います。
1
2
3
4
add_foreign_key :テーブル名, :指定先のテーブル名 [, オプション]
# (例)hogesテーブルにあるuser_idカラム対して外部キー制約をつける
add_foreign_key :hoges, :users
注意すべき点はすでに存在する外部キーに対して外部キー制約をつけるので、上の例だとhogesテーブルにuser_idカラムが存在しない場合はエラーになります。
オプションで「column」を使うと外部キーのカラム名を指定することができます。
例えばアソシエーションの定義で下記のように定義していたとします。
1
2
3
class Blog < ApplicationRecord
belongs_to :user, foreign_key: :author_id
end
上のように定義すると本来user_id
となるべき外部キーの名前をauthor_id
として使うことができます。
この場合、外部キー制約のカラム名もauthor_id
を指定しなくてはなりません。
そんなときに使うのがcolumnオプション
です。
上の例の場合は下記のように使用します。
1
2
# (例)blogsテーブルにあるauthor_idカラム対して外部キー制約をつける
add_foreign_key :blogs, :users, column: :author_id
remove_foreign_key
外部キーを削除するときに使います。
1
remove_foreign_key :テーブル名, :指定先のテーブル名
あらかじめコードが書かれている状態で作成してみよう
カラムを追加したりする際には上記のようにコードを記述するのですが、実はマイグレーションファイルを作成する際のマイグレーション名は何でも構いません。
ですがマイグレーション名を下記のようにとあるパターンの通りに記述すると作成されたマイグレーションファイルにコードが書かれた状態で作成することができます。
例えばカラムを追加する際のマイグレーションファイルを作成する際のマイグレーション名は下記のように記述します。
1
$ rails g migration Add追加するカラム名To追加するテーブル名 追加するカラム名:型
スペースを入れない代わりに先頭の文字を大文字にするのがポイントです。
ではusersテーブルにstring型でnameというカラムを追加するマイグレーションファイルを作成してみましょう。
1
$ rails g migration AddNameToUsers name:string
このコマンドで作成したマイグレーションファイルを開くと下記のような状態で作成されます。
1
2
3
4
5
class AddNameToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :name, :string
end
end
逆に今作成したnameカラムをusersテーブルから削除するマイグレーションファイルを作成するときは下記のようなコードを入力します。
1
$ rails g migration RemoveNameFromUsers name:string
このコマンドで作成したマイグレーションファイルを開くと下記のような状態で作成されます。
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 |
パターンがあるものはパターン通りに作成するのが良いでしょう。
マイグレーションファイルを作成する際の注意点
上のパターンが定義されていないマイグレーションファイルを作成するときも変更内容がわかるような名前をつけることが大事です。
特に規則はないですが、誰がみてもわかりやすい名前をつけましょう。
1
2
# カラム名を変更する時の例
RenameFrom変更前のカラム名To変更後のカラム名Onテーブル名
またマイグレーション名は同じ名前で作成することはできません。
1
2
invoke active_record
identical db/migrate/20XXXXXXXXXXXX_add_name_to_users.rb
このようなエラーが出てしまうので、マイグレーション名は被らないようにしましょう。
可逆的なマイグレーションファイルを作成しよう
マイグレーションファイルが不可逆的だとrailsはうまくロールバックできません。
不可逆的というのは逆方向に戻す方法がわからないことを言います。
例として下記のマイグレーションファイルをみてみましょう。
このマイグレーションファイルを実行後ロールバックするとどうなるでしょう?
1
2
3
4
5
6
class マイグレーション名 < ActiveRecord::Migration[5.2]
def change
# text型からstring型へ変更
change_column :hoges, :name, :string
end
end
実行はもちろんうまくいきます。
ですがロールバックする前はtext型であったという情報が書かれていません。
なのでrailsは前の状態に戻す方法がわからないためエラーとなります。
こういうときには下記のように記述をしておきます。
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状態のファイルは編集・削除しないよう慎重に編集してみてください。
▼ データベースについて不安がある方は、基礎から一通り学べる以下の参考書を利用すると良いでしょう。
PCがあれば、データベースの動作と役割が「全部」わかる!
この記事のまとめ
- マイグレーションファイルとは、データベースの設計図のようなもの
- このファイルを実行することにより記述した内容がデータベースに反映される
- 同じ名前で作成することは出来ないので注意しよう!