ActiveRecordにおける規約
テーブルを定義する前にActiveRecordにおける規約を確認しておきましょう。
カラム名
ActiveRecordには、利用する目的に応じてカラム名が決められているものがあります。
予約済みカラム名 | 利用目的 |
---|---|
id | デフォルトでは、テーブルの主キーとして使われる |
テーブル名の単数形_id | 外部キーとして使われる |
created_at | レコード作成時に現在の日時を自動的に設定する |
updated_at | レコード作成や更新時に現在の日時を自動的に設定する |
以前、phpMyAdminとSQLの章で作成したemployees
とdepartments
のテーブルの「主キー」と「外部キー」の名前は、ActiveRecordの規約に従ったものです。
テーブルの主キーはid
で、外部キーは親テーブル名の単数形_id
になります。
モデルのクラス名とテーブル名
ActiveRecordでは、いくつかの規約に従うことで「モデルのクラス」と「データベースのテーブル」を自動的に紐付けることができます。
規約(命名ルール) | 例: 単純語 | 例: 複合語 | |
---|---|---|---|
モデルのクラス名 | キャメルケース ・単数形 ・語頭は大文字 ・アンダースコアなし |
User |
AdminUser |
対応するテーブル名 | スネークケース ・複数形 ・語頭は小文字 ・語はアンダースコアで区切る |
users |
admin_users |
テーブル名は、モデルのクラス名を複数形・語頭を小文字にした名前になります。
例えばUser
という名前のモデルのクラスがある場合、自動的に紐付けられるテーブルは複数形のusers
になります。
なるほど!departmentsテーブルに紐付けを行う場合は、モデルのクラス名をDepartmentにすれば良いんだね。
その通り!employeesテーブルの場合は、Employeeになるよね。命名ルールを学べたので、次はモデルを作成してみよう
モデルの作成
モデルのクラスとは、ApplicationRecord
を継承したクラスのことです。
モデルのクラス名は、先ほどの命名ルールで学習したように「先頭大文字の単数形」に指定することで、クラス名を複数形にしたテーブル名に対応付けられます。
1
2
class モデルのクラス名 < ApplicationRecord
end
例えば、次のようにモデルのクラス名をDepartment
に指定すると、departments
という名前のテーブルに対応付けることができます。
1
2
class Department < ApplicationRecord
end
モデルのクラスは「ApplicationRecord
クラスを継承したクラス」のことで、テーブルを操作するモデル本体になります。そのためRailsでは、モデルのクラスのことを「モデル」と指す場合が多いです。
つまり「モデルの作成」は、ApplicationRecordを継承するモデルのクラスを作成することなんだね。
手動でモデルのクラスを作成することも可能だけど、Railsではモデルに必要なファイルを自動で生成する便利なコマンドが用意されているよ。
モデルの作成・削除コマンド
モデルを作成するときはrails generate
コマンドを使えば、モデルのクラスだけではなく、関連するファイルも自動で生成することができます。
モデル名には、モデルのクラス名を指定します。
1
rails generate model モデル名
上記のコマンドを実行すると、複数のファイルが自動で生成されます。
※ 以下のファイル名は、コマンドのモデル名をDepartment
に指定した場合です。
自動生成されるファイル | 説明 |
---|---|
app/models/department.rb | モデルクラスのファイル テーブルを操作するためのモデル本体 |
db/migrate/xxxxxxx_create_departments.rb | マイグレーションファイル テーブルを作成するための情報を含む |
test/models/department_test.rb | モデルクラスのテスト用ファイル |
test/fixtures/departments.yml | テストデータを投入するためのファイル |
この章では、上2つのファイルだけを学習します。1つ目のファイルは、モデルクラスのファイルで、2つ目のファイルはテーブルを作成するためのファイルです。
モデル名を間違えた場合は、rails destroy
コマンドで取り消すことができます。
1
rails destroy model モデル名
上記のコマンドを実行すると、rails generate
コマンドで自動生成されたファイルが全て取り消されます。
rails generateコマンドでは、モデルに関連するファイルが生成されるだけで、テーブルがすぐに作られる訳ではない点もおさえておこう!
モデルを作成してみよう
それでは、rails generateコマンドを利用して2つのモデルを作成してみましょう。
作成するモデルは、Department
モデルとEmployee
モデルです。rails generateコマンドは、アプリケーションのディレクトリで実行させます。
以下のコマンドを実行して、カレントディレクトリをemployee_management
ディレクトリに変更しましょう。
1
cd ~/environment/employee_management
1
pwd
実行すると、以下のように~/environment/employee_management
と表示されます。
以下のコマンドをemployee_management
ディレクトリで実行して、Departmentモデルクラスと関連するファイル一式を生成してみましょう。
1
rails g model department
実行すると、複数のファイルが自動生成されます。以下の緑枠で囲う2つのファイルがDepartmentモデルのクラス、departmentsテーブルを作成するためのファイルです。
※ db/migrateディレクトリに生成されるファイル名の先頭の数字は、一致している必要はありません。
app/models
ディレクトリに生成されたdepartment.rb
は、Departmentモデルのクラスファイルです。departmentsテーブルを操作するために必要なファイルです。
db/migrate
ディレクトリの方は、departmentsテーブルを作成するために必要なファイルです。ファイル名はYYYYMMDDHHMMSS_create_departments.rb
のような形式になります。先頭部分には、ファイルが生成された日時が追加されます。
以下のようにdepartment.rb
を開くと、ApplicationRecord
クラスを継承したDepartment
クラスが定義されています。
モデルのクラスは「ApplicationRecordクラスを継承したクラス」で、それらのクラスを「モデル」と指すと学びましたね。Departmentモデルは、department.rb
に定義されるDepartmentクラスのことです。
テーブル作成に必要なYYYYMMDDHHMMSS_create_departments.rb
については、マイグレーションで学習します。
以下のコマンドをemployee_management
ディレクトリで実行して、Employeeモデルクラスと関連するファイル一式を生成してみましょう。
1
rails g model employee
実行すると、複数のファイルが自動生成されます。以下の緑枠で囲う2つのファイルがEmployeeモデルのクラス、employeesテーブルを作成するためのファイルです。
※ db/migrateディレクトリに生成されるファイル名の先頭の数字は、一致している必要はありません。
app/models/employee.rb
は、Employeeモデルのファイルです。db/migrate/YYYYMMDDHHMMSS_create_employees.rb
は、employeesテーブルを作成するために必要なファイルです。
以下のようにemployee.rb
を開くと、ApplicationRecord
クラスを継承したEmployee
クラスが定義されています。これがEmployee
モデルになります。
テーブル作成に必要なYYYYMMDDHHMMSS_create_employees.rb
については、次のマイグレーションで学習します。
rails generate
コマンドでは、モデルに関連するファイルが自動で生成されるだけで、テーブルを作成している訳ではありません。
phpMyAdminにログインして、employee_management_development
にテーブルが作成されていないことを確認しましょう。
Railsでデータベースにテーブルを作成するには「マイグレーション」を利用します。
マイグレーション
ActiveRecordには、マイグレーション(migration)と呼ばれる機能があります。マイグレーションとは、データベースの構造を作成、変更および削除できる仕組みのことです。
マイグレーションを利用する主なメリットとして、以下のようなことが挙げられます。
- データベース構造の定義をRubyで記述することができる
- バージョン管理を行うことができる
SQLでテーブルの作成や変更を加える場合は、CREATE TABLE
文やALTER TABLE
文などのデータ定義言語を使用しましたね。Railsでは、これらの処理を行うメソッドが提供されているので、SQLのデータ操作言語を使わずにRubyで記述することができます。
バージョン管理では変更履歴を記録できるので、後から巻き戻れるようにしておけます。
マイグレーションってなんだか難しそうだなぁ・・・。
簡単に説明すると、SQLを使わずにテーブルやカラムなどの構造を変更できる仕組みだよ!一つ一つ順を追いながら説明するので、安心してね
マイグレーションの仕組み
マイグレーションの全体像をざっくりと把握してみましょう。マイグレーションを利用して、データベースにdepartments
テーブルを作成する流れで確認してみます。
まずは、どのようなテーブルにするのかを「マイグレーションファイル」に記述します。具体的には必要なカラムやデータ型、オプションなどを定義します。そして、「railsコマンド」を実行することで、データベースに定義を反映させることができます。
また「マイグレーション管理テーブル」に、マイグレーションファイル名のタイムスタンプが挿入されることで、どこまで実行されているかを管理することができます。
ここで覚えておきたいポイントは、マイグレーションファイルに構造を定義するだけでは、DBに反映されないってことだよ。定義を反映させるには、railsコマンドの実行が必要だと頭に入れておこう!
マイグレーションファイルの基礎
マイグレーションファイルとは、データベースの構造を定義するためのファイルのことです。もう少し簡単に説明すると、どのようなテーブルにするのかを定義するファイルです。
マイグレーションファイルはActiveRecord::Migration
クラスを継承したクラスであることが条件です。このクラスは、マイグレーションの実体になります。
1
2
3
4
5
6
7
8
class クラス名 < ActiveRecord::Migration[6.1]
def change
create_table :テーブル名 do |t|
t.timestamps
end
end
end
マイグレーションファイルはdb/migrate
ディレクトリ内に格納されており、ファイル名の先頭にはファイルが生成された日時の「タイムスタンプ」が追加されます。
このタイムスタンプは、マイグレーションを識別するためのものです。
rails generate
コマンドでモデルを作成すると、「モデルに対応するテーブル」を作成するためのマイグレーションファイルが自動的に生成されます。
Department
モデルを作成した際に、マイグレーションファイルも生成されましたね。
上記のマイグレーションファイルは、Department
モデルに対応するdepartments
テーブルを作成する設定で生成されます。
ファイルを開いてみると、クラスにはchange
というメソッドが定義されています。
1
2
3
4
5
6
7
8
class CreateDepartments < ActiveRecord::Migration[6.1]
def change
create_table :departments do |t|
t.timestamps
end
end
end
change
メソッドでは、create_table
というRailsのメソッドを利用してdepartmentsテーブルを作成します。上記の設定では、最低限必要なカラムしか作成されません。
テーブルに必要なカラムを指定できるように、マイグレーションファイルの基本的な書き方を学びましょう。
基本書式
データベースにテーブルを新規作成する場合は、change
メソッド内でcreate_table
メソッドを利用します。create_tableメソッドは、テーブル名とカラム定義を行えます。
テーブル名は、以下のようにcreate_table
の後に:テーブル名
と指定します。
1
2
3
4
5
6
7
class クラス名 < ActiveRecord::Migration[6.1]
def change
create_table :テーブル名 do |t|
end
end
end
create_table
メソッドには、ブロックを渡すことができます。|
と|
の間に指定されたブロック変数のt
は、カラムを定義するためのメソッドが提供されます。
以下のようにt.データ型
メソッドを利用して、カラムを定義します。
1
2
3
4
5
6
7
class クラス名 < ActiveRecord::Migration[6.1]
def change
create_table :テーブル名 do |t|
t.データ型 :カラム名, 制約名: 値
end
end
end
例えば、以下のusers
テーブルの場合は「非NULL制約」を設定したname
という名前のカラムが「VARCHAR型」で定義されます。
※ Railsでstring型を指定した場合、MySQL(MariaDB)側でVARCHAR型に置き換えられます。
1
2
3
4
5
6
7
8
class CreateUsers < ActiveRecord::Migration[6.1]
def change
create_table : users do |t|
t.string :name, null: false
#t.データ型 :カラム名, 制約名: 値
end
end
end
上記のマイグレーションファイルが実行された場合、users
テーブルにはname
カラムだけではなく、id
という名前の主キーが暗黙的に生成されます。
他にもt.timestamps
が指定される場合は、created_at
とupdated_at
という2つのカラムが生成されます。
1
2
3
4
5
6
7
8
9
class クラス名 < ActiveRecord::Migration[6.1]
def change
create_table :テーブル名 do |t|
t.データ型 :カラム名, 制約名: 値
t.timestamps #created_atとupdated_atというカラムを生成
end
end
end
ActiveRecordの規約では、利用する目的に応じてカラム名が決められているものがありましたね。主キーのid
だけではなく、t.timestamps
で生成されるcreated_at
とupdated_at
も予約済みのカラム名です。
予約済みカラム名 | 利用目的 |
---|---|
id | デフォルトでは、テーブルの主キーとして使われる |
テーブル名の単数形_id | 外部キーとして使われる |
created_at | レコード作成時に現在の日時を自動的に設定する |
updated_at | レコード作成や更新時に現在の日時を自動的に設定する |
カラム名だけではなく、Railsで利用できるデータ型や制約も確認してみましょう。
データ型
データ型は、テーブルに格納するデータの種類を限定するものでしたね。
Railsでは、create_table
メソッドのブロック内で「t.データ型
」メソッドを利用することで、カラムのデータ型を定義することができます。
1
2
3
4
5
6
7
class クラス名 < ActiveRecord::Migration[6.1]
def change
create_table :テーブル名 do |t|
t.データ型 :カラム名
end
end
end
Railsで利用できる主なデータ型は、以下の通りです。
メソッド名 | 定義できるデータ型 | 説明 |
---|---|---|
t.integer | INT型 | 数値 |
t. string | ※STRING型 | 文字列(短文) ※VARCHAR(255)型に置き換えられる |
t.text | TEXT型 | 文字列(長文) |
t.date | DATE型 | 日付 |
t.datetime | DATETIME型 | 日付と時刻 |
t.boolean | BOOLEAN型 | 真偽値 |
制約・オプション
制約とは、データベースに格納するデータが満たさなければならない条件のことでしたね。
Railsでは「t.データ型
」メソッドを利用することで、カラムに制約が設定できます。制約は、カラム名の後にカンマで区切り、制約名: 値
の形式で記述します。
1
2
3
4
5
6
7
class クラス名 < ActiveRecord::Migration[6.1]
def change
create_table :テーブル名 do |t|
t.データ型 :カラム名, 制約名: 値
end
end
end
Railsで利用できる主な「制約」や「オプション」は、以下の通りです。
制約・オプション | 制約名: 値 | 説明 |
---|---|---|
非NULL制約(NOT NULL制約) | null: false |
NULL(値が何もない状態)を禁止する |
デフォルト値 | default: 値 |
デフォルト値を指定する デフォルト値をNULLにする場合はnilを指定 |
limit | limit: 値 |
データ型の最大幅を指定する |
主キー制約の設定されたカラム(主キー)は、id
という名前で暗黙的に生成されるよ。
Railsでは、SQLと違って特に指定しなくても、主キーがデフォルトで生成されるんだね。
外部キー制約を設定する場合
Railsでは、カラムに外部キー制約を設定する場合はcreate_table
メソッドのブロック内で「t.references
」メソッドを利用します。
t.referencesメソッドでは、カラム名の後にforeign_key: true
を指定します。
1
2
3
4
5
6
7
class クラス名 < ActiveRecord::Migration[6.1]
def change
create_table :テーブル名 do |t|
t.references :カラム名, foreign_key: true
end
end
end
t.references
メソッドを利用する場合、カラム名に_id
の指定が不要になります。
ActiveRecordには、利用する目的に応じてカラム名が決められているものがあり、外部キーの場合は親テーブル名の単数形_id
でしたよね。
t.references
メソッドでは、カラム名に親テーブル名の単数形
を指定するだけで、親テーブル名の単数形_id
というカラムで生成されます。
以下はdepartment
ではなく、department_id
というカラム名で生成されます。
1
2
3
4
5
6
7
class クラス名 < ActiveRecord::Migration[6.1]
def change
create_table :テーブル名 do |t|
t.references :department, foreign_key: true
end
end
end
t.references
メソッドでは、カラムに自動でインデックスが付与されます。
マイグレーションファイルを編集してみよう
マイグレーションファイルを編集して、テーブルに必要なカラムを定義していきましょう。
以下のようにdb/migrate
ディレクトリ内に格納される2つのマイグレーションファイルを編集していきます。ファイル名の先頭部分は一致している必要はありません。
上記のファイルは、それぞれdepartments
テーブル、employees
テーブルを作成するためのファイルです。
まずは、Department
モデルを作成した際に自動で生成されたマイグレーションファイルを開きましょう。
ファイルを開いて、以下のような記述になっているかを確認しましょう。
1
2
3
4
5
6
7
8
class CreateDepartments < ActiveRecord::Migration[6.1]
def change
create_table :departments do |t|
t.timestamps
end
end
end
上記のマイグレーションファイルを編集して、departments
テーブルに必要なカラムを定義していきます。
departments
テーブルに必要なカラムは、以下のようにid
とname
です。
データ型と制約は、以下の通りです。
カラム名 | データ型 | 制約 | その他 |
---|---|---|---|
id | INT | 主キー制約(PRIMARY KEY) 非NULL制約(NOT NULL制約) |
AUTO_INCREMENT |
name | VARCHAR(30) | 非NULL制約(NOT NULL制約) |
上記の内容でdepartments
テーブルを作成するSQL文は、以下の通りでしたね。
1
2
3
4
5
CREATE TABLE departments (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(30) NOT NULL,
PRIMARY KEY(id) -- idに主キー制約を設定する
);
SQLでは主キーを設定しましたが、Railsではテーブルを作成するマイグレーションが実行されると、id
という名前の主キーが暗黙的に生成されます。そのため、マイグレーションファイルではname
カラムの定義だけを行います。
以下のようにマイグレーションファイルを編集して、name
カラムを定義しましょう。
1
2
3
4
5
6
7
8
9
class CreateDepartments < ActiveRecord::Migration[6.1]
def change
create_table :departments do |t|
t.string :name, null: false, limit: 30
t.timestamps #削除しないでおきましょう
end
end
end
次にEmployee
モデルを作成した際に自動で生成されたマイグレーションファイルを開きましょう。
ファイルを開いて、以下のような記述になっているかを確認しましょう。
1
2
3
4
5
6
7
8
class CreateEmployees < ActiveRecord::Migration[6.1]
def change
create_table :employees do |t|
t.timestamps
end
end
end
上記のマイグレーションファイルを編集して、employees
テーブルに必要なカラムを定義していきます。
employees
テーブルに必要なカラムは、以下のように4つのカラムです。外部キー制約は、子テーブルであるemployeesテーブルのdepartment_id
に設定します。
ほとんどのカラムには、非NULL制約を設定しますが、birthday
のカラムだけは、デフォルト値をNULL
にできるよう制約を設定しません。
その他のデータ型と制約は、以下の通りです。
カラム名 | データ型 | 制約 | その他 |
---|---|---|---|
id | INT | 主キー制約(PRIMARY KEY) 非NULL制約(NOT NULL制約) |
AUTO_INCREMENT |
name | VARCHAR(30) | 非NULL制約(NOT NULL制約) | |
birthday | DATE | デフォルト値: NULL |
|
department_id | INT | 外部キー制約(FOREIGN KEY) 非NULL制約(NOT NULL制約) |
上記の内容でemployees
テーブルを作成するSQL文は、以下の通りでしたね。
1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE employees (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(30) NOT NULL,
birthday date DEFAULT NULL,
department_id int(11) NOT NULL,
PRIMARY KEY(id), -- idに主キー制約を設定する
FOREIGN KEY(department_id) -- department_idに外部キー制約を設定する
REFERENCES departments(id) --親テーブルと親テーブルの主キーを指定する
ON DELETE RESTRICT -- 親テーブルに対する削除操作を拒否する
ON UPDATE RESTRICT -- 親テーブルに対する更新操作を拒否する
);
SQLではON DELETE
とON UPDATE
でRESTRICT
を指定することで、親テーブルに対する削除・更新操作を拒否していましたね。Railsでもt.references
メソッドのforeign_key
を利用して、同じように設定してみます。
以下のようにマイグレーションファイルを編集して、employees
テーブルのカラムを定義しましょう。
1
2
3
4
5
6
7
8
9
10
11
class CreateEmployees < ActiveRecord::Migration[6.1]
def change
create_table :employees do |t|
t.string :name, null: false, limit: 30
t.date :birthday, default: nil
t.references :department, foreign_key: { on_delete: :restrict, on_update: :restrict }
t.timestamps #削除しないでおきましょう
end
end
end
birthday
カラムに設定するデフォルト値は、null
ではなくnil
である点にも注意しましょう。
たしかマイグレーションファイルに記入しただけでは、データベースにテーブルを作成することができないよね。
その通りだよ。データベースに定義を適用させるには、railsコマンドでマイグレーションファイルを実行させる必要があるよ!
マイグレーションファイルを実行
マイグレーションファイルの実行は、rails db:migrate
コマンドを利用します。
1
rails db:migrate
rails db:migrate
コマンドは、まだ実行されていないマイグレーションファイルのchange
メソッドを実行します。
1
2
3
4
5
6
7
8
9
class CreateDepartments < ActiveRecord::Migration[6.1]
def change
create_table :departments do |t|
t.string :name, null: false, limit: 30
t.timestamps
end
end
end
マイグレーションファイルの実行順序は、ファイル名の先頭にあるタイムスタンプ(ファイルが生成された日時)が基準になります。
rails db:migrateコマンドを実行すると、どんな流れでデータベースに適用されるのかを図で確認していきましょう。
実行の流れを確認しよう
rails db:migrate
が実行されると、以下の図のようにschema_migrations
テーブルが調べられます。テーブルが存在しなければ作成されます。
schema_migrations
テーブルは、マイグレーションの実行履歴を管理するテーブルです。version
カラムの値は、マイグレーションファイルのタイムスタンプが入ります。
次にdb/migrate
ディレクトリ内に格納される全てのマイグレーションファイルが調べられます。そしてschema_migrations
テーブルと比較されます。
schema_migrations
テーブルに「タイムスタンプ値」が登録されてないマイグレーションファイルがあれば、データベースに適用されます。
最後にschema_migrations
テーブルが更新されます。
schema_migrations
テーブルに「20230214061519」という値があるということは、20230214061519_create_departments.rb
が実行されていることを意味します。
実行の流れをまとめると、以下の通りです。
- rails db:migrateを実行する
- schema_migrationsテーブルを調べる、テーブルが存在しなければ作成される
- db/migrateディレクトリ内に格納される全てのマイグレーションファイルを調べる
- schema_migrationsテーブルのバージョンと異なるバージョンがあれば、データベースに適用させる
- schema_migrationsテーブルを更新する
あとで詳しく説明しますが、schema_migrationsテーブルと齟齬が生じてエラーが起きる可能性があるので、実行完了後のマイグレーションファイル、つまりschema_migrationsテーブルに登録されるマイグレーションファイルは、絶対に編集や手動で削除しないように注意してください。
マイグレーションを実行して、テーブルを作成してみよう
それでは、rails db:migrateコマンドを利用して2つのテーブルを作成してみましょう。
データベースに作成するテーブルは、departments
テーブルとemployees
テーブルです。rails db:migrateコマンドは、アプリケーションのディレクトリで実行させます。
以下のコマンドを実行して、カレントディレクトリをemployee_management
ディレクトリに変更しましょう。
1
cd ~/environment/employee_management
1
pwd
実行すると、以下のように~/environment/employee_management
と表示されます。
以下のコマンドをemployee_management
ディレクトリで実行して、マイグレーションファイルで定義したテーブルをデータベースに適用させましょう。
1
rails db:migrate
実行すると、以下のように表示されます。数字部分は、一致する必要ありません。
phpMyAdminにログインして、employee_management_development
にテーブルが作成されていることを確認しましょう。
データベースにdepartments、employeesという名前のテーブルが無事に作成されているね!
あとは、マイグレーションの実行履歴を管理する「schema_migrations」という名前のテーブルも存在すればOKだよ。
departmentsテーブルを作成するためのマイグレーションファイルでは、以下のようにカラムを定義しましたね。
1
2
3
4
5
6
7
8
9
class CreateDepartments < ActiveRecord::Migration[6.1]
def change
create_table :departments do |t|
t.string :name, null: false, limit: 30
t.timestamps
end
end
end
phpMyAdminでdepartments
テーブルを確認してみましょう。
以下のようにnameカラムだけではなく、主キーであるid
が暗黙的に生成されています。またt.timestamps
によって、created_at
とupdated_at
という2つのカラムも生成されていますね。
employeesテーブルを作成するためのマイグレーションファイルでは、以下のようにカラムを定義しましたね。
1
2
3
4
5
6
7
8
9
10
11
class CreateEmployees < ActiveRecord::Migration[6.1]
def change
create_table :employees do |t|
t.string :name, null: false, limit: 30
t.date :birthday, default: nil
t.references :department, foreign_key: { on_delete: :restrict, on_update: :restrict }
t.timestamps
end
end
end
phpMyAdminでemployees
テーブルを確認してみましょう。
以下のようにマイグレーションファイルで定義したカラムが生成されています。そしてt.references
で指定したdepartment
は、department_id
というカラム名で生成されます。
実行の流れでは、schema_migrationsテーブルのversionカラムの値は、実行済みのマイグレーションファイルのタイムスタンプが入ると学びましたね。
データベースには、departments
テーブルとemployees
テーブルが作成されているので、以下のマイグレーションファイルは実行されているはずですよね。
phpMyAdminでschema_migrations
テーブルを確認してみましょう。
以下のようにschema_migrationsテーブルのversionカラムの値には、実行済みのマイグレーションファイルのタイムスタンプ(バージョン)が登録されています。
schema_migrationsテーブルによって、2つのマイグレーションファイルの実行が済んでいることがわかりましたね。
スキーマファイルを確認しよう
実はrails db:migrate
コマンドを実行すると、db:schema:dump
というコマンドも同時に呼び出されます。このコマンドは、スキーマファイルの作成や更新を行います。
スキーマファイルとは、現在のデータベースの状態を表すファイルのことです。スキーマファイルは、schema.rb
という名前でdb
ディレクトリ内に作成されます。
個別のマイグレーションファイルは、データベースの新しい「バージョン」とみなすことができるのに対して、スキーマファイルはマイグレーションファイルの集合です。
schema.rb
ファイルを開くと、現在のデータベースの状態を確認することができます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ActiveRecord::Schema.define(version: 2023_02_14_065344) do
create_table "departments", charset: "utf8mb4", force: :cascade do |t|
t.string "name", limit: 30, null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "employees", charset: "utf8mb4", force: :cascade do |t|
t.string "name", limit: 30, null: false
t.date "birthday"
t.bigint "department_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["department_id"], name: "index_employees_on_department_id"
end
add_foreign_key "employees", "departments"
end
1行目にあるversion
の値は、マイグレーションファイル名のタイムスタンプで、バージョンです。どのバージョンまでデータベースに適用されているかを表しています。
先ほどのマイグレーションの実行によって、データベースには「20230214065344」まで適用されているので、version
の値は2023_02_14_065344
になります。
スキーマファイルは、マイグレーションの実行によって自動で更新されるので、データベースの最新の状態を確かめることができるよ。
それでは、スキーマファイル(schema.rb)のversionの値が「schema_migrationsテーブル」の最終行の値であることを確認してみましょう。
※ 下の画像と値が一致している必要はありません。
マイグレーションの状況を表示
schema_migrationsテーブルのversionカラムには、実行済みのマイグレーションファイルのタイムスタンプ値が入るので、「マイグレーションファイルがどこまで実行されているか」を確かめることができます。
しかし、マイグレーションの状況はschema_migrationsテーブルを確認しなくてもrails db:migrate:status
コマンドを利用することで、すぐに調べることができます。
rails db:migrate:statusコマンド
1
rails db:migrate:status
上記のコマンドを実行すると、以下のようにマイグレーションの状況が表示されます。
Migration ID
は、マイグレーションファイル名のタイムスタンプです。Status
がup
であれば、そのマイグレーションファイルは実行済みで、データベースにも適用されている状況です。
1
2
3
4
5
6
database: データベース名
Status Migration ID Migration Name
--------------------------------------------------
up 20xxxxxxxxxxxx Create departments
up 20xxxxxxxxxxxx Create employees
上記のようにStatus
がup
のマイグレーションファイルは、Railsは既に実行済みであると認識しているので、rails db:migrate
を実行しても何も変更されません。
Status
がup
の場合は、schema_migrationsテーブルにもタイムスタンプが登録されてるってことだね。
そうだよ!schema_migrationsテーブルで管理されているから、Statusがupのマイグレーションファイルは、絶対に削除しないでね!
以下のようにStatus
がdown
であれば、そのマイグレーションファイルは実行されておらず、データベースにも適用されていない状況です。
1
2
3
4
5
6
database: データベース名
Status Migration ID Migration Name
--------------------------------------------------
down 20xxxxxxxxxxxx Create departments
down 20xxxxxxxxxxxx Create employees
カレントディレクトリをemployee_management
ディレクトリに変更して、rails db:migrate:status
コマンドを実行してみましょう。
1
cd ~/environment/employee_management
1
pwd
1
rails db:migrate:status
rails db:migrate:status
コマンドを実行すると、以下のようにStatus
がup
と表示されるので、どちらのマイグレーションファイルも実行済みだとわかります。
マイグレーションを前の状態に戻す
マイグレーションを利用するメリットとして、バージョン管理を行うことができる点が挙げられます。バージョン管理とは、いわばセーブデータの履歴のようなもので、作業の進捗をセーブデータのように保存し、後から巻き戻れるようにしておけます。
Railsのマイグレーションの場合は、実行したマイグレーションファイルのタイムスタンプをschema_migrationsテーブルに挿入することで、実行履歴を管理することができます。
このように変更履歴が記録されることで、データベースの構造を過去のある時点の状態に戻すことができます。この機能を「ロールバック」と呼びます。
ロールバックすると、schema_migrationsテーブルからもバージョンが削除されます。
マイグレーションファイルは、rails db:migrate
で一度実行すると再度実行できない仕組みになっています。一般に修正する場合は、履歴として残すために修正用のマイグレーションファイルを新たに作成する必要があります。
しかし、カラム名の間違えなど履歴に残す必要がない程度の修正(※1)であれば、ロールバックでマイグレーションの状態を戻し、修正を行い、マイグレーションを実行しなおします。
rails db:rollbackコマンド
マイグレーションのロールバックは、rails db:rollback
コマンドを利用します。
1
rails db:rollback
上記のコマンドを実行すると、以下のようにマイグレーションが1つ前の状態に戻ります。
先ほどのrails db:migrate:status
コマンドでマイグレーションの状況を調べたときは、データベースにemployees
テーブル作成まで適用されている状態でしたね。
この状況でrails db:rollback
を実行すると、マイグレーションが1つ前の状態に戻るので、データベースからemployees
テーブルが削除されます。
それでは、カレントディレクトリをemployee_management
ディレクトリに変更して、rails db:rollback
コマンドを実行してみましょう。
1
cd ~/environment/employee_management
1
pwd
1
rails db:rollback
rails db:rollback
を実行すると、ロールバックしたマイグレーションの情報がターミナルに出力されます。このロールバックで、データベースからemployees
テーブルが削除されたので、以下のようにdrop_table(:employees)
とも表示されています。
ロールバック後、マイグレーションの状況が更新されているかを確かめてみましょう。
1
rails db:migrate:status
rails db:migrate:status
を実行すると、以下のようにロールバックしたマイグレーションのStatus
がdown
と表示されます。
Status
がdown
であれば、そのマイグレーションファイルは実行されておらず、データベースにも適用されていない状況です。
schema_migrations
テーブルでは、実行済みのマイグレーションファイルのタイムスタンプを登録して、マイグレーションの実行履歴を管理しています。ロールバックしたマイグレーションは、Status
がdown
になり、まだ実行していない状態になります。
phpMyAdminにアクセスし、以下のようにschema_migrations
テーブルからロールバックしたバージョンが削除されていることを確かめてみましょう。
schema_migrations
テーブルの最終行の値は、現在データベースに適用されているマイグレーションのバージョンになります。
スキーマファイルとは、現在のデータベースの状態を表すファイルのことでしたね。
schema.rb
の1行目にあるversion
の値は、マイグレーションファイル名のタイムスタンプで、どのバージョンまでデータベースに適用されているかを表しています。
以下のようにversion
の値がschema_migrationsテーブルの最終行の値で、1つ前のマイグレーションファイル名のタイムスタンプであることを確かめてみましょう。
ロールバックにより1つ前のマイグレーションに戻るので、以下のようにversion
の値と共にdepartments
テーブル作成の定義だけが存在しています。
データベースにはdepartments
テーブル作成だけ適用されていることがわかりますね。
それでは、データベースでemployees
テーブルが削除されて、departments
テーブルだけが作成されているかを確かめてみましょう。
このようにrails db:rollback
コマンドを実行するだけで、自動的に関連するテーブルやファイルの内容が更新されて、データベースの構造を1つ前の状態に戻すことができます。
rails db:migrate
コマンドを実行して、データベースにemployees
テーブルを作成するマイグレーションを適用させましょう。
1
rails db:migrate
上記のコマンドを実行すると、以下のようにschema.rb
も更新されます。
続いて、以下のrails db:migrate:status
を実行して、マイグレーションの状況を確かめてみましょう。
1
rails db:migrate:status
上記のコマンドを実行すると、以下のようにemployees
テーブルを作成するマイグレーションのStatus
がup
と表示されるので、データベースに適用されている状況です。
最後にデータベースを確認してみましょう。
以下のようにschema_migrations
テーブルには、実行済みのマイグレーションのバージョンが挿入されます。データベースにはemployees
テーブルも作成されていますね。
注意点:本番環境では既存のマイグレーションを直接修正しない
すでに学習した内容ですが、マイグレーションファイルはrails db:migrate
で一度実行すると、再度実行できない仕組みになっています。
この仕組みは、個別のマイグレーションファイルを変更履歴として残し、「どのような変更が行われてきたか」を確認したり、過去のある状態に戻れるようにするためです。
ロールバックでは、マイグレーションを過去のバージョンに戻すことができます。ロールバックで修正を行う際、ケアレスミスなどの軽度な修正でも状況を見極める必要があります。
もし、チーム開発で共同作業者に影響が出る(masterにmergeしている)状況や本番環境でマイグレーションファイルが実行済みであれば、ロールバックで既存のマイグレーションファイルを直接変更してはいけません。
この状況では、ロールバックで既存のマイグレーションを直接修正するのではなく、影響を小さく抑えるために修正用のマイグレーションファイルを新たに作成する必要があります。
masterにmergeしたマイグレーションファイルや本番環境で実行済みのマイグレーションファイルは変更しちゃダメってことだね!
その通りだよ。さっそくマイグレーションファイルの作成方法を学んでみよう!
マイグレーションファイルを作成
マイグレーションファイルは、モデルと併せて作成する以外にも、rails generate migration
コマンドでマイグレーションファイル単体を作成する方法があります。
rails generate model
- モデルと併せてファイルを作成するrails generate migration
- マイグレーションファイル単体を作成する
モデルと併せて自動生成されるマイグレーションファイルは、モデルに対応するテーブルを作成するためのものです。作成済みのテーブルに変更を加える場合は、新たにマイグレーションファイル単体を作成して変更を加えていきます。
rails generate migrationコマンド
マイグレーションでは、「クラス名」とタイムスタンプ後の「ファイル名」を一致させる必要があります。rails generate migration
コマンドを利用することで、適切な名前で単体のマイグレーションファイルを作成することができます。
1
rails generate migration クラス名
クラス名は、キャメルケース(CamelCase)で指定します。ファイル名の後半は、クラス名のスネークケース(snake_case)で作成されます。
例えば、以下のようにクラス名を「AddAgeToUsers」と指定した場合、作成されるマイグレーションファイルの名前は、「20xxxxxxxxxxxx_add_age_to_users.rb」になります。
1
rails generate migration AddAgeToUsers
1
2
3
4
class AddAgeToUsers < ActiveRecord::Migration[6.1]
def change
end
end
クラス名は自由に付けることができますが、マイグレーションのクラス名やファイル名を確認するだけで処理内容を識別しやすいように具体的な名前を付けるようにしましょう。
一般にマイグレーションのクラス名は「処理内容 + テーブル名」にします。
オプション:追加/削除コードの自動生成
本章では学習のため使用しませんが、rails generate migration
コマンドでは、クラス名などをある形式に則ることで、追加や削除に必要なコードも自動生成することができます。
カラム追加では「Addカラム名Toテーブル名」、カラム削除では「Removeカラム名Fromテーブル名」のクラス名を指定し、カラム名や型が続く形式にします。
1
rails generate migration クラス名 カラム名:データ型
1
rails generate migration AddAgeToUsers age:integer
上記のコマンドを実行すると、以下のようなマイグレーションファイルが自動で生成されます。
1
2
3
4
5
class AddAgeToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :age, : integer
end
end
テーブルにカラムを追加する
テーブルにカラムを追加する場合は、rails generate migration
で指定する「クラス名」を「Addカラム名Toテーブル名」にします。
1
rails generate migration クラス名
1
rails generate migration Addカラム名Toテーブル名
例えばusers
テーブルにage
カラムを追加する場合、以下のようにクラス名を「AddAgeToUsers」と指定します。
1
rails generate migration AddAgeToUsers
上記のコマンドを実行すると、以下のようにファイル名の後半と一致するクラス名のマイグレーションファイルが作成されます。クラス内には、change
メソッドが定義されます。
1
2
3
4
class AddAgeToUsers < ActiveRecord::Migration[6.1]
def change
end
end
テーブルにカラムを追加する場合、change
メソッド内でadd_column
メソッドを利用します。以下のように追加するカラムを定義することができます。例ではusers
テーブルに追加するage
カラムに対して、INT型、非NULL制約を設定しています。
1
2
3
4
5
class AddAgeToUsers < ActiveRecord::Migration[6.1]
def change
add_column :テーブル名, :カラム名, :データ型, オプション
end
end
1
2
3
4
5
class AddAgeToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :age, :integer, null: false
end
end
それでは、マイグレーションファイルを作成して、employeesテーブルにINT型のageカラムを追加してみましょう。以下のコマンドを順番に実行してください。
1
cd ~/environment/employee_management
1
rails g migration AddAgeToEmployees
上記のコマンドを実行すると、以下のようにdb/migrate
ディレクトリにマイグレーションファイルが作成されます。※ タイムスタンプ値は一致する必要はありません。
まずは、db/migrate
ディレクトリ内にあるマイグレーションファイルを開きましょう。
以下のようにadd_column
メソッドを利用して、追加するageカラムを定義しましょう。
1
2
3
4
5
class AddAgeToEmployees < ActiveRecord::Migration[6.1]
def change
add_column :employees, :age, :integer
end
end
現時点では、マイグレーションファイルに追加するカラムを定義しただけなので、データベースに適用していない状況です。rails db:migrate:status
コマンドを実行して、 作成したマイグレーションファイルのStatus
がdown
であることを確認しましょう。
1
rails db:migrate:status
それでは、rails db:migrate
コマンドを利用して、未実行のマイグレーションファイルを実行させて、データベースに適用させましょう。
1
rails db:migrate
上記のコマンドを実行すると、以下のようにマイグレーションファイルが実行されます。
続いて、以下のようにrails db:migrate:status
コマンドを実行して、 作成したマイグレーションファイルのStatus
がup
であることを確認しましょう。
1
rails db:migrate:status
最後にphpMyAdminにログインして、employeesテーブルにageカラムが追加されていることを確認しましょう。
テーブルからカラムを削除する
テーブルからカラムを削除する場合は、rails generate migration
で指定する「クラス名」を「Removeカラム名Fromテーブル名」にします。
1
rails generate migration クラス名
1
rails generate migration Removeカラム名Fromテーブル名
例えばusers
テーブルからage
カラムを削除する場合、以下のようにクラス名を「RemoveAgeFromUsers」と指定します。
1
rails generate migration RemoveAgeFromUsers
上記のコマンドを実行すると、以下のようにファイル名の後半と一致するクラス名のマイグレーションファイルが作成されます。クラス内には、change
メソッドが定義されます。
1
2
3
4
class RemoveAgeFromUsers < ActiveRecord::Migration[6.1]
def change
end
end
テーブルからカラムを削除する場合、change
メソッド内でremove_column
メソッドを利用します。以下のように削除するカラムを定義することができます。例ではusers
テーブルから削除するカラムとして、INT型、非NULL制約が設定されるageカラムを定義しています。
1
2
3
4
5
class RemoveAgeFromUsers < ActiveRecord::Migration[6.1]
def change
remove_column :テーブル名, :カラム名, :データ型, オプション
end
end
1
2
3
4
5
class RemoveAgeFromUsers < ActiveRecord::Migration[6.1]
def change
remove_column :users, :age, :integer, null: false
end
end
それでは、マイグレーションファイルを作成して、employeesテーブルからINT型のageカラムを削除してみましょう。以下のコマンドを順番に実行してください。
1
cd ~/environment/employee_management
1
rails g migration RemoveAgeFromEmployees
上記のコマンドを実行すると、以下のようにdb/migrate
ディレクトリにマイグレーションファイルが作成されます。※ タイムスタンプ値は一致する必要はありません。
まずは、db/migrate
ディレクトリ内にあるマイグレーションファイルを開きましょう。
以下のようにremove_column
メソッドを利用して、削除するageカラムを定義しましょう。
1
2
3
4
5
class RemoveAgeFromEmployees < ActiveRecord::Migration[6.1]
def change
remove_column :employees, :age, :integer
end
end
現時点では、マイグレーションファイルに削除するカラムを定義しただけなので、データベースに適用していない状況です。rails db:migrate:status
コマンドを実行して、 作成したマイグレーションファイルのStatus
がdown
であることを確認しましょう。
1
rails db:migrate:status
それでは、rails db:migrate
コマンドを利用して、未実行のマイグレーションファイルを実行させて、データベースに適用させましょう。
1
rails db:migrate
上記のコマンドを実行すると、以下のようにマイグレーションファイルが実行されます。
続いて、以下のようにrails db:migrate:status
コマンドを実行して、 作成したマイグレーションファイルのStatus
がup
であることを確認しましょう。
1
rails db:migrate:status
最後にphpMyAdminにログインして、employeesテーブルからageカラムが削除されていることを確認しましょう。
この記事のまとめ
- マイグレーションとは、データベースの構造を作成、変更および削除できる仕組みのこと
- マイグレーションはバージョン管理を行うので、実行したマイグレーションファイルは削除してはいけない!
この記事で学んだことをTwitterに投稿して、アウトプットしよう!
Twitterの投稿画面に遷移します