すでにメンバーの場合は

無料会員登録

GitHubアカウントで登録 Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

登録がまだの方はこちらから

Pikawakaにログイン

GitHubアカウントでログイン Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

Railsでのデータベース設計と操作を学ぼう

この記事で出来るようになること

はじめに

概要

この章では、Railsを使用したデータベース操作の基本について学びます。初めに、MVCアーキテクチャを振り返り、その中でモデルの基本概念を理解します。続いて、ActiveRecordの概要とそれがモデルとどのように連携するかを学びます。

その後、データベース接続の設定、データベースの作成と削除方法、モデルとテーブルの命名規約について詳しく学びます。また、モデルの作成方法やマイグレーションの基本についても解説します。この章を通じて、Railsでのモデルとデータベース操作に関する基本的な概念とテクニックを習得しましょう。

目標

この章の目標
  • データベースの基本的な概念を理解し、作成と削除を実行できる
  • ActiveRecordの規約に従って、正確なモデルとテーブルを設計できる
  • マイグレーションの基本的な仕組みを理解し、ファイルを作成・実行できる
  • データベースのスキーマを確認し、マイグレーションの状況を管理できる

必要な前提条件・事前準備

この章を始める前に、リレーショナルデータベースに関する基本用語と概念、SQLでの基本的なデータベース操作についての理解が必要です。また、SQLを学習した前章で作成したテーブルの削除が完了していることを確認してください。

必要なもの・知識

以下の手順に従って、適切なタイムゾーンの設定を行いましょう。

タイムゾーンの設定

タイムゾーン(Time Zone)とは、世界中の異なる場所で時間を調整するための仕組みです。地球が24時間で回るため、各地域で時間を統一的に扱うために、地球をいくつかの区分に分けています。

多くの場合、サーバーには世界の時刻の標準であるUTC(協定世界時)が設定されます。グローバルなアプリケーションを開発・運用する場合であれば、タイムゾーンはUTCで統一させますが、日本国内では、UTCに9時間を足したJST(日本標準時)が用いられます。

今回は、RailsのタイムゾーンとOSのタイムゾーンを「UTC」から「JST」に変更します。

Railsのタイムゾーンを設定しよう

Railsのタイムゾーンの設定は、config/application.rbで行います。

タイムゾーンを設定

config/application.rbを開いて、デフォルトのタイムゾーンを設定しましょう

config.time_zoneでは、アプリケーションやActive Recordで使用するデフォルトのタイムゾーンを設定することができます。以下のようにapplication.rbの19行目のコメントを外し、タイムゾーンを東京に設定しましょう。

config/application.rb | タイムゾーンを東京に設定する
1
config.time_zone = "Tokyo"

タイムゾーンを東京に設定する

データベースの処理の際に使うタイムゾーンを設定しましょう

application.rbの20行目に以下の1行を追加して、タイムゾーンを設定しましょう。

config/application.rb | データベースの処理の際に使うタイムゾーンをlocalに設定
1
config.active_record.default_timezone = :local

データベースの処理の際に使うタイムゾーンをlocalに設定

OSのタイムゾーンを設定しよう

Cloud9の環境に設定されるタイムゾーンを確認しましょう

以下のコマンドを実行して、Cloud9の環境に設定されるタイムゾーンがUTCであることを確認しましょう。

ターミナル | Cloud9の環境に設定されるタイムゾーンを確認
1
date

Cloud9の環境に設定されるタイムゾーンを確認

Cloud9の環境に設定されるタイムゾーンをJSTに変更しましょう

以下のコマンドを上から順番に実行して、タイムゾーンをJSTに変更しましょう。

※ コマンドは、タイプミスを減らすためにコピー&ペーストしてください。現時点でsedlnコマンドを理解する必要はありません。

ターミナル | 設定ファイルをUTCからAsia/Tokyoに変更する
1
sudo sed -i -e "/^ZONE=/c\ZONE=Asia/Tokyo" /etc/sysconfig/clock
ターミナル | シンボリックリンクを作成する
1
sudo ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
ターミナル | Cloud9を再起動する
1
sudo reboot

最後のsudo rebootを実行すると、以下のようにCloud9が再起動されます。

Cloud9再起動

再起動後、以下のようにdateを実行して、Cloud9の環境に設定されるタイムゾーンがUTCではなく、JSTに変更されていることを確認しましょう。

JSTに変更

タイムゾーンの設定が完了したら、次のステップに進みましょう!

ぴかわかさん

1.Railsでのデータベース操作の理解

1-1.MVCアーキテクチャでの処理の流れ

Pikawakaカリキュラムでは、Webアプリケーションのデータ保存先としてリレーショナルデータベースを利用します。前回は、SQLを使ってリレーショナルデータベースを操作する方法を学びました。

今回は、Ruby on Railsを使用してリレーショナルデータベースを操作する方法を学びます。

Railsでは、以前に学んだ通り、MVCアーキテクチャが採用されています。このアーキテクチャでは、アプリケーションが「Model(モデル)」「View(ビュー)」「Controller(コントローラー)」という3つの主要な要素に分けられ、それぞれが特定の役割を担うように設計されています。特に、モデルはデータベースとのやり取りを担当します。

MVCアーキテクチャ 役割 フォルダ
モデル(M) データベースとのやりとりを担当する app/models/
ビュー(V) ユーザーに表示される画面の内容を担当する app/views/
コントローラー(C) ユーザーのリクエストの処理と
適切なレスポンスの返却を担当する
app/controllers/

これまでの学習では、モデルを除くルーティング、コントローラ、ビューを使ってページを表示する方法について学んできました。

モデルを組み合わせた処理の全体的な流れは、以下の通りです。

それでは、次にモデルの役割と機能について詳しく学びましょう。モデルはアプリケーションのデータとそのロジックを管理し、データベースとの間の橋渡しをします。これを理解することは、Railsで効率的にアプリケーションを開発するために不可欠です。

1-2.モデルの基本概念

Ruby on Railsのモデルは、アプリケーションのデータベースとのやり取りを担当し、ユーザーからの情報(例えば、ウェブサイト上で入力されたデータ)をデータベースに保存したり、必要に応じてデータベースから情報を取り出したりします。

このプロセスは、コントローラからの指示に従って行われます。モデルが処理したデータはコントローラに提供され、その後コントローラはこの情報をビューに渡して、ユーザーに表示される出力を生成します。

他にもモデルは、データに関するルールやロジック(例えば、データがどのように保存されるべきか、どのような形式で取り出されるべきかなど)を担います。

ぴかわかさん

Railsのモデルはapp/models/ディレクトリに配置されます。初期状態では、このディレクトリにはモデルのファイルが存在しません。新しいモデルを作成する際には、必要に応じてこのディレクトリに新しいファイルを追加してモデルを定義します。

モデルのファイル内では、特定のクラスを定義します。
このクラスには、ApplicationRecordというクラスを継承する必要があります。

モデルのファイル例
1
2
class クラス名 < ApplicationRecord
end

ApplicationRecordクラスを継承することで、モデルはデータベースとのやり取りに必要な一連の機能にアクセスできるようになります。これは、ApplicationRecordがデータベース操作を簡素化するActiveRecord::Baseクラスを継承しているためです。

この継承により、モデルのクラスは「Active Record」というライブラリの機能を利用でき、データベース操作をより効率的かつ直感的に行えるようになります。

ぴっかちゃん

モデルには「Active Record」というライブラリの機能が使えるってこと?

その通りだよ!「Active Record」のおかげで、モデルはデータベースとのやり取りを簡単にできるんだ。これから「Active Record」の具体的な機能について学ぶと、もっとはっきりするよ。

ぴかわかさん

1-3.ActiveRecordの概要

Ruby on Railsのモデルは通常、ApplicationRecordクラスを継承し、ActiveRecordという強力なRubyのgemを利用して、データベースとのやり取りを行います。

ActiveRecordは、オブジェクトリレーショナルマッピング(Object-Relational Mapping、略称ORM)の機能を提供します。これにより、RailsのモデルはリレーショナルデータベースのレコードをRubyのオブジェクトとして扱うことができます。

例えば、新しいユーザーをデータベースに追加する際、従来のSQL操作ではINSERT構文を使用してテーブルにレコードを挿入します。

SQLの場合 | 新しいユーザーをデータベースに追加する
1
INSERT INTO users(name, age) VALUES('山田花子', 34);

しかし、ActiveRecordを使えば、Railsのモデルを介して同じ操作をRubyのコードで簡単に実行できます。オブジェクトを操作する感覚でデータを扱うことが可能になります。

Railsの場合 | 新しいユーザーをデータベースに追加する
1
2
user = User.new(name: "山田花子", age: 34)
user.save

ActiveRecordを使用すると、Railsのモデルを通じてデータベースのレコードをより簡単に管理でき、Railsアプリケーションの開発がより迅速かつ効率的になります。これにより、開発者は複雑なSQLクエリを直接書くことなく、Railsのモデルを使ってデータベースのレコードを作成、読み取り、更新、削除することができます。

ぴっかちゃん

ActiveRecordって便利だよね。でも、前の章で学んだSQLの知識って必要なのかな?ActiveRecordの使い方をマスターすればいい気がするけど…。

ActiveRecordは確かに便利で、SQLをうまく隠してくれるけど、データベースがどう動いているかを理解するためには、SQLの基本を知ることが大切だよ。特に、複雑なデータベース操作やパフォーマンスの最適化を考えるときに、SQLの知識がとても役立つんだ!

ぴかわかさん

オブジェクトリレーショナルマッピング(ORM)の役割

オブジェクトリレーショナルマッピング(ORM)は、オブジェクト指向プログラミング言語とリレーショナルデータベース間のギャップを埋める重要な役割を果たします。

オブジェクト指向プログラミングとリレーショナルデータベースは、データの構造が根本的に異なります。オブジェクト指向では、データと関連する振る舞い(メソッド)がクラスやオブジェクト(インスタンス)にカプセル化されています。対照的に、リレーショナルデータベースはテーブル、レコード、カラムを用いてデータを管理します。

この構造的な違いを効率的に解決するため、オブジェクトリレーショナルマッピング(ORM)が広く使用されています。ORMは、リレーショナルデータベースのテーブルやレコードをオブジェクト指向プログラミング内のクラスやインスタンスにマッピング(対応付け)します。

これにより、プログラム内でのオブジェクト操作はデータベースの操作と直接結びつき、より直感的かつ効率的なデータベース管理が可能になります。

ORMの使用により、データベースのCRUD(作成、読み出し、更新、削除)操作をプログラミング言語のコードを通じて簡単に実行できるようになり、SQLクエリを直接書く手間が省けます。また、ORMはデータベースの整合性を維持する機能を提供し、アプリケーション全体の品質が向上します。

Ruby on Railsでは、すでに学習した通り、ActiveRecordという強力なORMツールが標準で使用されています。

ぴかわかさん

2.データベース接続と管理の基本

2-1.データベース接続の設定

Ruby on RailsでActiveRecordを使用してリレーショナルデータベースに接続する際には、configディレクトリ内のdatabase.ymlファイルでデータベースの接続情報を設定する必要があります。

database.ymlファイルでは、開発、テスト、本番環境ごとに異なるデータベース設定を定義することができます。ActiveRecordは、このファイルに記述された設定に基づいてデータベースへの接続を管理します。

database.yml

rails newコマンドを使用してRailsアプリケーションを作成する際、database.ymlファイルは自動的に生成されます。

database.ymlファイルの詳細については、既に「データベースの準備」のセクションで学習しています。より深い理解を求める場合は、そのセクションを参照してください。

ぴっかちゃん

たしか「rails db:create」コマンドでデータベースを作成する時、database.ymlに記載された設定に基づいてデータベースが作成されるんだったよね!

その通りだよ!さらに、環境ごとに異なる設定もできたよね。もし忘れている人がいたら、もう一度復習してみてね。

ぴかわかさん

2-2.データベースの作成と削除

これまで、phpMyAdminの画面で操作したり、SQLを実行してデータベースを作成や削除してきました。しかし、Railsではrailsコマンドを使ってこれらの操作が可能です。

例 | データベースを作成する
1
rails db:create
例 | データベースを削除する
1
rails db:drop

これらのコマンドは、database.ymlの設定に基づいてデータベースを作成または削除します。

ぴっかちゃん

このコマンドだけでデータベースの作成や削除ができるのは便利だね!

アプリケーション作成準備の章でデータベースはもう作成済みだけど、コマンド操作に慣れるためにデータベースを削除して、もう一度作成してみよう!

ぴかわかさん

データベースを削除しよう

アプリケーション作成準備の章では、rails db:createコマンドを実行して、以下のように「開発環境」と「テスト環境」のデータベースを作成しましたね。

2つのデータベースを作成

phpMyAdminでも、以下のように2つのデータベースを確認することができます。

2つのデータベース

railsコマンドを使用してデータベースを削除しましょう。

以下のコマンドを順番に実行して、作成済みの「開発環境」と「テスト環境」のデータベースを削除しましょう。

ターミナル | カレントディレクトリをemployee_managementに変更する
1
cd ~/environment/employee_management
ターミナル | employee_managementのディレクトリにいることを確認
1
pwd
ターミナル(~/environment/employee_management) | データベースを削除する
1
rails db:drop

rails db:dropを実行すると、以下のように2つのデータベースが削除されます。

データベース削除

phpMyAdminにアクセスして、データベースが削除されたことを確認しましょう

まず、以下のコマンドを順番に実行してサーバを起動しましょう。

ターミナル | カレントディレクトリを移動する
1
cd ~/environment/employee_management/public/phpMyAdmin-5.1.1-all-languages
ターミナル(~/environment/employee_management/public/phpMyAdmin-5.1.1-all-languages)| サーバーを起動する
1
php -S 127.0.0.1:8081

次にphpMyAdminにログインしてみましょう。
そこで、以下のように2つのデータベースが削除されていることを確認できます。

データベース削除を確認する

データベースを作成しよう

rails db:createを実行すると、database.ymlの設定に従って「開発環境」と「テスト環境」のデータベースが作成されます。

データベースも環境ごとに違う

ぴっかちゃん

本番環境のデータベースは作成されないんだね。

本番環境のデータベースを作成する時は、コマンドにRAILS_ENV=productionを追加してrails db:createを実行するんだよ。

ぴかわかさん
railsコマンドを使用してデータベースを作成しましょう。

以下のコマンドを順番に実行して、開発環境とテスト環境のデータベースを作成しましょう。

ターミナル | カレントディレクトリをemployee_managementに変更する
1
cd ~/environment/employee_management
ターミナル | employee_managementのディレクトリにいることを確認
1
pwd
ターミナル(~/environment/employee_management) | データベースを作成する
1
rails db:create

rails db:createを実行すると、以下のように2つのデータベースが作成されます。

データベース作成

railsコマンドで作成された2つのデータベースは、database.ymlに設定されている開発環境とテスト環境のデータベースです。database.ymlで設定されたデータベース名とrailsコマンドで作成されるデータベース名は、以下のように一致しています。

開発環境とテスト環境のデータベース

phpMyAdminにアクセスし、下の画像に示されているように、2つのデータベースが作成されていることを確認できます。

2つのデータベース

このようにrailsコマンドを使用すると、ターミナル上で簡単にデータベースの作成や削除の操作を行うことができます。

ポイント
  1. データベースの作成は、rails db:createを実行する
  2. データベースの削除は、rails db:dropを実行する
  3. 上記ではdatabase.ymlの設定に従ってデータベース作成や削除をする

3. モデルとテーブルの命名規約

Railsでは、モデルを通じてデータベースとのやり取りが行われます。これらのモデルは、特定のクラスを継承することでActiveRecordの機能を活用し、データベースとの効率的なコミュニケーションを可能にすることを学びましたね。

ActiveRecordは「規約による設定」(Convention Over Configuration)の原則に基づいており、特定の命名規則に従うことで、モデルとデータベースのテーブル間の自動的な関連付けが行われます。

この命名規則を適切に理解し適用することにより、Railsアプリケーションのデータベース構造を効率的かつ直感的に設計・管理することができます。次に、カラム名の規約やモデルのクラス名とテーブル名の関係について詳しく学んでいきましょう。

3-1.カラム名の規約

ActiveRecordでは、特定の目的のために予め定められたカラム名が使用されます。これらのカラムはRailsの内部で重要な役割を果たし、データベース操作を効率的かつ自動的に行うことが可能になります。

以下の表に、予約済みのカラム名とその利用目的を示します。

予約済みカラム名 利用目的
id デフォルトでは、テーブルの主キーとして使われる
テーブル名の単数形_id 外部キーとして使われる
created_at レコード作成時の現在日時を自動的設定
updated_at レコード更新時の現在日時を自動設定

例えば、idは各レコードを一意に識別する主キーとして、テーブル名の単数形_idは外部キーとして機能します。

以前、phpMyAdminとSQLの章で作成したemployeesdepartmentsテーブルの「主キー」と「外部キー」も、このActiveRecordの規約に従っています。

主キーと外部キー

created_atupdated_atカラムは、それぞれレコードの作成日時と更新日時を自動的に記録するために使用されます。これらのカラムにより、レコードの追加や最終更新時刻を簡単に追跡でき、データの整合性を維持するのに役立ちます。

3-2.モデルのクラス名とテーブル名

ActiveRecordでは、いくつかの規約に従うことで「モデルのクラス」と「データベースのテーブル」を自動的に関連付けられます。

規約(命名ルール) 例: 単純語 例: 複合語
モデルのクラス名 キャメルケース
・単数形
・語頭は大文字
・アンダースコアなし
User AdminUser
対応するテーブル名 スネークケース
・複数形
・語頭は小文字
・語はアンダースコアで区切る
users admin_users

テーブル名は、モデルのクラス名を複数形・語頭を小文字にした名前になります。

例えばUserという名前のモデルのクラスがある場合、自動的に紐付けられるテーブルは複数形のusersになります。

userモデルの紐付け先

ぴっかちゃん

なるほど!departmentsテーブルに紐付けを行う場合は、モデルのクラス名をDepartmentにすれば良いんだね。

その通り!employeesテーブルの場合は、Employeeになるよね。命名ルールを学べたので、次はモデルを作成してみよう

ぴかわかさん
ポイント
  1. 規約に従えば、モデルのクラスとテーブルを自動的に関連付けられる
  2. モデルのクラス名は、語頭は大文字で単数形にする(例: User
  3. 対応するテーブル名は、語頭は小文字で複数形にする(例: users

4.モデル操作の基本

4-1.モデルの作成方法

モデルのクラスとは、ApplicationRecordを継承したクラスのことです。

モデルのクラス名は、先ほどの命名ルールで学習したように「先頭大文字の単数形」に指定することで、クラス名を複数形にしたテーブル名に対応付けられます。

モデルのクラス
1
2
class モデルのクラス名 < ApplicationRecord
end

例えば、次のようにモデルのクラス名をDepartmentに指定すると、departmentsという名前のテーブルに対応付けることができます。

例: Departmentモデルクラス
1
2
class Department < ApplicationRecord
end

モデルのクラスは「ApplicationRecordクラスを継承したクラス」のことで、テーブルを操作するモデル本体になります。そのためRailsでは、モデルのクラスのことを「モデル」と指す場合が多いです。

ぴっかちゃん

つまり「モデルの作成」は、ApplicationRecordを継承するモデルのクラスを作成することなんだね。

手動でモデルのクラスを作成することも可能だけど、Railsではモデルに必要なファイルを自動で生成する便利なコマンドが用意されているよ。

ぴかわかさん

4-2.モデル作成・削除のコマンド

モデルを作成するときはrails generateコマンドを使えば、適切な命名規則や継承のルールを持つモデルファイルや関連するファイルが自動的に生成されます。

モデルを作成する際には、Railsアプリケーションのルートディレクトリで以下のようにコマンドを実行します。モデル名には、モデルのクラス名を指定します。

モデル作成の基本文法
1
2
rails generate model モデル名
# または「rails g 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
2
rails destroy model モデル名
# または「rails d model モデル名」としても同様に削除できます

上記のコマンドを実行すると、rails generateコマンドで自動生成されたファイルが全て取り消されます。

ぴっかちゃん

rails generate modelを使うと、テーブルも作ってくれるのかな?

モデルの関連ファイルは生成されるけど、それだけじゃテーブルはすぐに作られないんだよ。この点、ちゃんと覚えておいてね!

ぴかわかさん

4-3.実際にモデルを作成する手順

それでは、rails generateコマンドを使用してDepartmentモデルとEmployeeモデルを作成しましょう。このコマンドは、アプリケーションのディレクトリで実行する必要があります。

アプリケーションのディレクトリに移動しましょう

まず、カレントディレクトリをアプリケーションのディレクトリに変更しましょう。以下のコマンドを実行して、カレントディレクトリをemployee_managementディレクトリに変更します。

ターミナル | カレントディレクトリをemployee_managementディレクトリに変更する
1
cd ~/environment/employee_management
ターミナル | employee_managementディレクトリにいることを確認する
1
pwd

実行すると、以下のように~/environment/employee_managementと表示されます。

employee_managementディレクトリ

Departmentモデルを生成しましょう

次に、rails generateコマンドを使用して、Departmentモデルを生成します。以下のコマンドをemployee_managementディレクトリで実行してください。

ターミナル | Departmentモデルを生成する
1
rails g model department

実行すると、Departmentモデルのクラスファイルおよびdepartmentsテーブルを作成するためのファイルが自動生成されます。生成されるファイルは以下の通りです。

※ db/migrateディレクトリに生成されるファイル名の先頭にある数字は、一致する必要はありません。

departmentモデル作成

  • app/models/department.rb:Departmentモデルのクラスファイル
  • db/migrate/YYYYMMDDHHMMSS_create_departments.rb:departmentsテーブルを作成するマイグレーションファイル

ファイルの位置関係は以下の画像に示されています。

ぴっかちゃん

app/models/department.rbは、departmentsテーブルを操作するのに必要なんだよね!

その通り!一方で、db/migrateディレクトリにあるファイルは、departmentsテーブルを作成するために必要だよ。このファイルについては、マイグレーションで詳しく学習するよ。

ぴかわかさん
department.rbファイルを開いてみましょう

department.rbを開くと、ApplicationRecordクラスを継承するDepartmentクラスが以下のように定義されています。

department.rb

モデルのクラスは「ApplicationRecordクラスを継承したクラス」として定義され、これらを「モデル」と呼びます。したがって、Departmentモデルはdepartment.rbに定義されるDepartmentクラスを指します。

Employeeモデルを生成しましょう

次に、同様の手順でEmployeeモデルを生成します。

ターミナル | Employeeモデルを生成する
1
rails g model employee

実行すると、Employeeモデルのクラスファイルおよびemployeesテーブルを作成するためのファイルが自動生成されます。これらのファイルは以下の通りです。

※ db/migrateディレクトリに生成されるファイル名の先頭の数字は、一致している必要はありません。

employeeモデル作成

  • app/models/employee.rb:Employeeモデルのクラスファイル
  • db/migrate/YYYYMMDDHHMMSS_create_employees.rb:employeesテーブルを作成するマイグレーションファイル

ファイルの位置関係は以下の画像に示されています。

employee.rbを開くと、ApplicationRecordクラスを継承するEmployeeクラスが以下のように定義されています。こちらのクラスがEmployeeモデルを指します。

employeeモデル

データベースにテーブルがまだ作成されていないことを確認しましょう

rails generateコマンドは、モデルに関連するファイルが自動的に生成するだけで、テーブルは作成されません。

phpMyAdminにログインし、employee_management_developmentデータベースにテーブルがまだ作成されていないかを確認してみましょう。

以下の画像に示されているように、テーブルはまだ作成されていません。

マイグレーション実行前

Railsでデータベースにテーブルを作成するには、次に学習する「マイグレーション」を利用します。

ポイント
  1. モデルのクラスとは、ApplicationRecordクラスを継承したクラスのこと
  2. モデルのクラスを「モデル」と指す場合が多い
  3. モデルの作成は、rails generateコマンドを使えば、モデルのクラスと関連するファイル一式を自動で生成することができる

5.マイグレーションの基礎

ActiveRecordには、マイグレーション(migration)という機能があります。マイグレーションとは、データベースの構造を作成、変更、または削除できる仕組みです。

マイグレーションの主なメリットは、以下の通りです。

  • データベース構造(テーブルの作成や変更など)をRubyで記述できる。
  • バージョン管理ができる。(変更履歴を記録し、必要に応じて以前の状態に戻せる)

SQLでテーブルの作成や変更をする場合、CREATE TABLEALTER TABLEといったデータ定義言語を使用します。しかし、RailsではActiveRecordを介して、これらの処理をRubyで行うためのメソッドが提供されているため、SQLの命令を使わずにRubyコードで記述することが可能となります。

ぴっかちゃん

マイグレーションって、ちょっと難しそう…。

簡単に言うと、SQLを使わずにRubyでテーブルやカラムの構造を変更できる仕組みなんだ。順を追って説明するから、心配しないでね。

ぴかわかさん

5-1. マイグレーションの仕組み

マイグレーションの全体像についてざっくりと理解しましょう。例として、マイグレーションを使ってデータベースにdepartmentsテーブルを作成する流れを見てみます。

最初に、どのようなテーブルを作成するかを「マイグレーションファイル」に記述します。ここでは必要なカラム、データ型、オプションなどを定義します。その後、「railsコマンド」を実行することで、これらの定義をデータベースに反映させることができます。

マイグレーションの仕組み

さらに、「マイグレーション管理テーブル」にはマイグレーションファイルのタイムスタンプが記録され、どのマイグレーションが実行されたかが管理されます。

大切なポイントは、マイグレーションファイルにテーブルの構造を定義しても、それだけではデータベースに反映されないということ。定義をデータベースに適用するためには、railsコマンドを実行する必要があるよ!

ぴかわかさん

5-2.マイグレーションファイルの基本

マイグレーションファイルは、データベースの構造を定義するためのファイルです。簡単に説明すると、「どのようなテーブルを作成するか」を定義するファイルです。

マイグレーションファイルは、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モデル作成

このマイグレーションファイルは、Departmentモデルに対応するdepartmentsテーブルを作成する設定で生成されます。

ファイルを開くと、クラスにはchangeというメソッドが定義されています。

db/migrate/20xxxxxxxxxxxx_create_departments.rb
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メソッドを使用してdepartmentsテーブルを作成します。上記では、基本的なカラムのみが作成されます。

テーブルに必要なカラムを指定する方法を理解するために、次にマイグレーションファイルの基本的な書式について学びましょう。

ポイント
  1. マイグレーションファイルは、データベース構造の定義に使用される
  2. マイグレーションファイルは、db/migrateディレクトリ内に格納される
  3. マイグレーションファイルのファイル名には、そのファイルが生成された日時を示すタイムスタンプが先頭に追加される

5-3.基本的な書式

データベースにテーブルを新規作成する際には、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を使ってカラムを定義します。このt変数には、カラムのデータ型を指定するためのメソッド(例:t.string, t.integerなど)が提供されます。

カラムの定義は、以下のように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カラムがstring型で定義されます。Railsでstring型を指定すると、MySQL(MariaDB)ではVARCHAR型に置き換えられます。

例 | 非NULL制約を設定したnameカラムを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_atupdated_atの2つのカラムも生成されます。

マイグレーションファイル
1
2
3
4
5
6
7
8
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_atupdated_atも予約済みのカラム名に含まれます。

予約済みカラム名 利用目的
id デフォルトでは、テーブルの主キーとして使われる
テーブル名の単数形_id 外部キーとして使われる
created_at レコード作成時に現在の日時を自動的に設定する
updated_at レコード作成や更新時に現在の日時を自動的に設定する
ポイント
  1. create_tableで新しいテーブルを定義する
  2. t.データ型を使ってカラムの型と名前を指定する
  3. ブロック変数tを利用してカラムの詳細な定義を行う
ポイント
  1. マイグレーションファイルを利用してテーブルを作成すると、idカラムの主キーを自動的に生成できる
  2. t.timestampsを指定すると、created_atupdated_atのカラムが生成される

5-4.データ型

データ型は、テーブルに格納するデータの種類を限定すると学習しましたね。

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型 真偽値

これらのデータ型は、create_tableメソッド内でカラムを定義する際に使用され、テーブル内の各カラムが保持するデータの種類を指定します。

5-5.制約とオプション

制約とは、データベースに格納されるデータが満たすべき条件を指します。

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で使用可能な主な制約とオプションは、データベース内のデータ整合性を保つために重要です。以下の表は、Railsで利用できる一般的な制約とオプションを示しており、これらはマイグレーションファイル内でカラム定義時に指定されます。

制約・オプション 制約名: 値 説明
非NULL制約(NOT NULL制約) null: false NULL(値が何もない状態)を禁止する
デフォルト値 default: 値 デフォルト値を指定する
デフォルト値をNULLにする場合はnilを指定
limit limit: 値 データ型の最大幅を指定する

制約を使ってデータの整合性を保つことが、データベース設計の重要な部分なんだ。

ぴかわかさん
ぴっかちゃん

そうなんだね。Railsでは制約設定が簡単にできて、安心だね!

5-6.外部キー制約の設定

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

ちなみに外部キーを手動で設定するのとは違って、Railsでは主キーは特に指定しなくてもidという名前で自動的に生成されるんだよ。

ぴかわかさん
ぴっかちゃん

Railsは自動で色々やってくれるから、便利だね!

ポイント
  1. t.referencesを使用すると、親テーブル名の単数形_idという形の外部キー制約付きカラムが自動生成される
  2. 外部キー制約はデータベースの整合性を保つために重要である
  3. foreign_key: trueオプションを使用することで、外部キー制約を強制し、データの整合性を保証する

6.マイグレーションの実践

マイグレーションは、Railsアプリケーションのデータベース構造を定義し、変更するための強力なツールです。ここでは、マイグレーションファイルの編集、そして実行に至るまでのプロセスを段階的に学びます。

6-1.マイグレーションファイルの編集

マイグレーションファイルを編集して、テーブルに必要なカラムを定義していきましょう。

以下のようにdb/migrateディレクトリ内に格納される2つのマイグレーションファイルを編集していきます。ファイル名の先頭部分は一致している必要はありません。

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

上記のファイルは、それぞれdepartmentsテーブル、employeesテーブルを作成するためのファイルです。

departmentsテーブルを作成するためのマイグレーションファイルを開きましょう

まずは、Departmentモデルを作成した際に自動で生成されたマイグレーションファイルを開きましょう。

departmentsテーブルを作成するためのマイグレーションファイル

ファイルを開いて、以下のような記述になっているかを確認しましょう。

db/migrate/20xxxxxxxxxxxx_create_departments.rb
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テーブルに必要なカラムを定義してみましょう

departmentsテーブルに必要なカラムは、以下のようにidnameです。

作成するテーブル

データ型と制約は、以下の通りです。

カラム名 データ型 制約 その他
id INT(11) 主キー制約(PRIMARY KEY)
非NULL制約(NOT NULL制約)
AUTO_INCREMENT
name VARCHAR(30) 非NULL制約(NOT NULL制約)

上記の内容でdepartmentsテーブルを作成するSQL文は、以下の通りでしたね。

SQL | departmentsテーブルを作成する
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カラムを定義しましょう。

db/migrate/20xxxxxxxxxxxx_create_departments.rb
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
employeesテーブルを作成するためのマイグレーションファイルを開きましょう

次にEmployeeモデルを作成した際に自動で生成されたマイグレーションファイルを開きましょう。

employeesテーブルを作成するためのマイグレーションファイル

ファイルを開いて、以下のような記述になっているかを確認しましょう。

db/migrate/20xxxxxxxxxxxx_create_employees.rb
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テーブルに必要なカラムを定義してみましょう

employeesテーブルに必要なカラムは、以下のように4つのカラムです。外部キー制約は、子テーブルであるemployeesテーブルのdepartment_idに設定します。

外部キー制約の設定

ほとんどのカラムには、非NULL制約を設定しますが、birthdayのカラムだけは、デフォルト値をNULLにできるよう制約を設定しません。

その他のデータ型と制約は、以下の通りです。

カラム名 データ型 制約 その他
id INT(11) 主キー制約(PRIMARY KEY)
非NULL制約(NOT NULL制約)
AUTO_INCREMENT
name VARCHAR(30) 非NULL制約(NOT NULL制約)
birthday DATE デフォルト値:
NULL
department_id INT(11) 外部キー制約(FOREIGN KEY)
非NULL制約(NOT NULL制約)

上記の内容でemployeesテーブルを作成するSQL文は、以下の通りでしたね。

SQL | employeesテーブルを作成する
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 DELETEON UPDATERESTRICTを指定することで、親テーブルに対する削除・更新操作を拒否していましたね。Railsでもt.referencesメソッドのforeign_keyを利用して、同じように設定してみます。

以下のようにマイグレーションファイルを編集して、employeesテーブルのカラムを定義しましょう。

db/migrate/20xxxxxxxxxxxx_create_employees.rb
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コマンドでマイグレーションファイルを実行させる必要があるよ!

ぴかわかさん

6-2.マイグレーションファイルの実行

マイグレーションファイルの実行は、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コマンドを実行すると、どんな流れでデータベースに適用されるのかを図で確認していきましょう。

ぴかわかさん

6-3.実行プロセスの確認

rails db:migrateが実行されると、以下の図のようにschema_migrationsテーブルが調べられます。テーブルが存在しなければ作成されます。

schema_migrationsテーブルは、マイグレーションの実行履歴を管理するテーブルです。versionカラムの値は、マイグレーションファイルのタイムスタンプが入ります。

rails db:migrateの流れ

次にdb/migrateディレクトリ内に格納される全てのマイグレーションファイルが調べられます。そしてschema_migrationsテーブルと比較されます。

schema_migrationsテーブルに「タイムスタンプ値」が登録されてないマイグレーションファイルがあれば、データベースに適用されます。

データベースに適用

最後にschema_migrationsテーブルが更新されます。

schema_migrationsテーブルに「20230214061519」という値があるということは、20230214061519_create_departments.rbが実行されていることを意味します。

実行履歴を管理

実行の流れをまとめると、以下の通りです。

  1. rails db:migrateを実行する
  2. schema_migrationsテーブルを調べる、テーブルが存在しなければ作成される
  3. db/migrateディレクトリ内に格納される全てのマイグレーションファイルを調べる
  4. schema_migrationsテーブルのバージョンと異なるバージョンがあれば、データベースに適用させる
  5. schema_migrationsテーブルを更新する

あとで詳しく説明しますが、schema_migrationsテーブルと齟齬が生じてエラーが起きる可能性があるので、実行完了後のマイグレーションファイル、つまりschema_migrationsテーブルに登録されるマイグレーションファイルは、絶対に編集や手動で削除しないように注意してください。

6-4.マイグレーションによるテーブルの作成

それでは、rails db:migrateコマンドを利用して2つのテーブルを作成してみましょう。

データベースに作成するテーブルは、departmentsテーブルとemployeesテーブルです。rails db:migrateコマンドは、アプリケーションのディレクトリで実行させます。

カレントディレクトリをアプリケーションのディレクトリに変更しましょう

以下のコマンドを実行して、カレントディレクトリをemployee_managementディレクトリに変更しましょう。

ターミナル | カレントディレクトリをemployee_managementディレクトリに変更する
1
cd ~/environment/employee_management
ターミナル | employee_managementディレクトリにいることを確認する
1
pwd

実行すると、以下のように~/environment/employee_managementと表示されます。

employee_managementディレクトリ

rails db:migrateコマンドを利用して、データベースにテーブルを作成しよう

以下のコマンドをemployee_managementディレクトリで実行して、マイグレーションファイルで定義したテーブルをデータベースに適用させましょう。

ターミナル | 未実行のマイグレーションファイルを実行させる
1
rails db:migrate

実行すると、以下のように表示されます。数字部分は、一致する必要ありません。

未実行のマイグレーションファイルを実行

データベースにテーブルが作成されていることを確かめてみよう

phpMyAdminのページを再読み込みし、employee_management_developmentにテーブルが作成されていることを確認しましょう。

テーブルを確認する

ぴっかちゃん

データベースにdepartments、employeesという名前のテーブルが無事に作成されているね!

あとは、マイグレーションの実行履歴を管理する「schema_migrations」という名前のテーブルも存在すればOKだよ。

ぴかわかさん
departmentsテーブルに定義したカラムを確認しよう

departmentsテーブルを作成するためのマイグレーションファイルでは、以下のようにカラムを定義しましたね。

db/migrate/20xxxxxxxxxxxx_create_departments.rb
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_atupdated_atという2つのカラムも生成されていますね。

departmentsテーブル

employeesテーブルに定義したカラムを確認しよう

employeesテーブルを作成するためのマイグレーションファイルでは、以下のようにカラムを定義しましたね。

db/migrate/20xxxxxxxxxxxx_create_employees.rb
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というカラム名で生成されます。

employeesテーブルに定義したカラム

schema_migrationsテーブルを確認してみよう

実行の流れでは、schema_migrationsテーブルのversionカラムの値は、実行済みのマイグレーションファイルのタイムスタンプが入ると学びました。

データベースには、departments テーブルとemployeesテーブルが作成されているので、以下のマイグレーションファイルは実行されているはずです。

マイグレーションファイルの実行順序

phpMyAdminでschema_migrationsテーブルを確認してみましょう。

以下のようにschema_migrationsテーブルのversionカラムの値には、実行済みのマイグレーションファイルのタイムスタンプ(バージョン)が登録されています。

schema_migrationsテーブル

schema_migrationsテーブルによって、2つのマイグレーションファイルの実行が済んでいることがわかりましたね。

ぴかわかさん

6-5.スキーマファイルの検証

実はrails db:migrateコマンドを実行すると、db:schema:dumpというコマンドも同時に呼び出されます。このコマンドは、スキーマファイルの作成や更新を行います。

スキーマファイルとは、現在のデータベースの状態を表すファイルのことです。スキーマファイルは、schema.rbという名前でdbディレクトリ内に作成されます。

個別のマイグレーションファイルは、データベースの新しい「バージョン」とみなすことができるのに対して、スキーマファイルはマイグレーションファイルの集合です。

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.rb)のversionの値が「schema_migrationsテーブル」の最終行の値であることを確認してみましょう。

※ 下の画像と値が一致している必要はありません。

スキーマファイル

schema_migrationsテーブル

6-6.マイグレーション状況の表示

schema_migrationsテーブルのversionカラムには、実行済みのマイグレーションファイルのタイムスタンプ値が入るので、「マイグレーションファイルがどこまで実行されているか」を確かめることができます。

マイグレーションの状況

しかし、マイグレーションの状況はschema_migrationsテーブルを確認しなくてもrails db:migrate:statusコマンドを利用することで、すぐに調べることができます。

rails db:migrate:statusコマンド

マイグレーションの状況を表示する
1
rails db:migrate:status # ここでは実行しません

上記のコマンドを実行すると、以下のようにマイグレーションの状況が表示されます。

Migration IDは、マイグレーションファイル名のタイムスタンプです。Statusupであれば、そのマイグレーションファイルは実行済みで、データベースにも適用されている状況です。

ターミナル | マイグレーションファイルが実行済みの場合
1
2
3
4
5
6
database: データベース名

 Status   Migration ID    Migration Name
--------------------------------------------------
up 20xxxxxxxxxxxx Create departments
up 20xxxxxxxxxxxx Create employees

上記のようにStatusupのマイグレーションファイルは、Railsは既に実行済みであると認識しているので、rails db:migrateを実行しても何も変更されません。

ぴっかちゃん

Statusupの場合は、schema_migrationsテーブルにもタイムスタンプが登録されてるってことだね。

そうだよ!schema_migrationsテーブルで管理されているから、Statusがupのマイグレーションファイルは、絶対に削除しないでね!

ぴかわかさん

以下のようにStatusdownであれば、そのマイグレーションファイルは実行されておらず、データベースにも適用されていない状況です。

ターミナル | マイグレーションファイルが未実行の場合
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コマンドを実行してみましょう。

ターミナル | カレントディレクトリをemployee_managementに変更する
1
cd ~/environment/employee_management
ターミナル | employee_managementのディレクトリにいることを確認
1
pwd
マイグレーションの状況を表示する
1
rails db:migrate:status

rails db:migrate:statusコマンドを実行すると、以下のようにStatusupと表示されるので、どちらのマイグレーションファイルも実行済みだとわかります。

マイグレーションファイルも実行済み

7.データベースの変更と修正の基本

開発過程ではデータベースの構造変更が頻繁に生じます。このセクションでは、データベースの変更や修正を行う基本的な手法を詳しく学んでいきます。

まず、「マイグレーションのロールバック」について学びます。これは、誤って行ったデータベースの変更を元に戻すための重要な機能です。ロールバックは、誤った変更を修正する際や、以前の状態に戻す際に不可欠です。

続いて、データベースに新しい項目を追加したり、不要な項目を削除する方法を学びます。これには新しいマイグレーションファイルを作成する必要があります。それでは、具体的な学習に進みましょう。

7-1.マイグレーションのロールバック

マイグレーションを利用するメリットとして、バージョン管理を行うことができる点が挙げられます。バージョン管理とは、いわばセーブデータの履歴のようなもので、作業の進捗をセーブデータのように保存し、後から巻き戻れるようにしておけます。

Railsのマイグレーションの場合は、実行したマイグレーションファイルのタイムスタンプをschema_migrationsテーブルに挿入することで、実行履歴を管理することができます。

バージョン管理

このように変更履歴が記録されることで、データベースの構造を過去のある時点の状態に戻すことができます。この機能を「ロールバック」と呼びます。

ロールバックすると、schema_migrationsテーブルからもバージョンが削除されます。

ロールバック

マイグレーションファイルは、rails db:migrateで一度実行すると再度実行できない仕組みになっています。一般に修正する場合は、履歴として残すために修正用のマイグレーションファイルを新たに作成する必要があります。

しかし、カラム名の間違えなど履歴に残す必要がない程度の修正(※1)であれば、ロールバックでマイグレーションの状態を戻し、修正を行い、マイグレーションを実行しなおします。

rails db:rollbackコマンド

マイグレーションのロールバックは、rails db:rollbackコマンドを利用します。

1つ前の状態に戻す
1
rails db:rollback

上記のコマンドを実行すると、以下のようにマイグレーションが1つ前の状態に戻ります。

1つ前の状態に戻す

rails db:rollbackを実行して、マイグレーションを1つ前の状態に戻してみましょう

先ほどのrails db:migrate:statusコマンドでマイグレーションの状況を調べたときは、データベースにemployeesテーブル作成まで適用されている状態でしたね。

マイグレーションファイルも実行済み

この状況でrails db:rollbackを実行すると、マイグレーションが1つ前の状態に戻るので、データベースからemployeesテーブルが削除されます。

それでは、カレントディレクトリをemployee_managementディレクトリに変更して、rails db:rollbackコマンドを実行してみましょう。

ターミナル | カレントディレクトリをemployee_managementに変更する
1
cd ~/environment/employee_management
ターミナル | employee_managementのディレクトリにいることを確認
1
pwd
ターミナル | 1つ前の状態に戻す
1
rails db:rollback

rails db:rollbackを実行すると、ロールバックしたマイグレーションの情報がターミナルに出力されます。このロールバックで、データベースからemployeesテーブルが削除されたので、以下のようにdrop_table(:employees)とも表示されています。

rails db:rollback実行

rails db:migrate:statusを実行して、マイグレーションの状況を確かめてみよう

ロールバック後、マイグレーションの状況が更新されているかを確かめてみましょう。

マイグレーションの状況を表示する
1
rails db:migrate:status

rails db:migrate:statusを実行すると、以下のようにロールバックしたマイグレーションのStatusdownと表示されます。

ロールバック

Statusdownであれば、そのマイグレーションファイルは実行されておらず、データベースにも適用されていない状況です。

schema_migrationsテーブルの実行履歴が削除されているかを確かめてみよう

schema_migrationsテーブルでは、実行済みのマイグレーションファイルのタイムスタンプを登録して、マイグレーションの実行履歴を管理しています。ロールバックしたマイグレーションは、Statusdownになり、まだ実行していない状態になります。

phpMyAdminにアクセスし、以下のようにschema_migrationsテーブルからロールバックしたバージョンが削除されていることを確かめてみましょう。

schema_migrationsテーブル

schema_migrationsテーブルの最終行の値は、現在データベースに適用されているマイグレーションのバージョンになります。

schema_migrationsテーブルの最終行の値とschema.rbのversionを確かめましょう

スキーマファイルとは、現在のデータベースの状態を表すファイルのことでしたね。
schema.rbの1行目にあるversionの値は、マイグレーションファイル名のタイムスタンプで、どのバージョンまでデータベースに適用されているかを表しています。

以下のようにversionの値がschema_migrationsテーブルの最終行の値で、1つ前のマイグレーションファイル名のタイムスタンプであることを確かめてみましょう。

schema_migrationsテーブルの最終行の値

1つ前のマイグレーションファイル名のタイムスタンプ

ロールバックにより1つ前のマイグレーションに戻るので、以下のようにversionの値と共にdepartmentsテーブル作成の定義だけが存在しています。

データベースにはdepartmentsテーブル作成だけ適用されていることがわかりますね。

departmentsテーブル作成の定義

employeesテーブルが削除されているかを確かめてみよう

それでは、データベースでemployeesテーブルが削除されて、departmentsテーブルだけが作成されているかを確かめてみましょう。

employeesテーブルが削除されている

このようにrails db:rollbackコマンドを実行するだけで、自動的に関連するテーブルやファイルの内容が更新されて、データベースの構造を1つ前の状態に戻すことができます。

ぴかわかさん
マイグレーションを実行して元通りにしておきましょう

rails db:migrateコマンドを実行して、データベースにemployeesテーブルを作成するマイグレーションを適用させましょう。

~/environment/employee_management
1
rails db:migrate

上記のコマンドを実行すると、以下のようにschema.rbも更新されます。

続いて、以下のrails db:migrate:statusを実行して、マイグレーションの状況を確かめてみましょう。

~/environment/employee_management
1
rails db:migrate:status

上記のコマンドを実行すると、以下のようにemployeesテーブルを作成するマイグレーションのStatusupと表示されるので、データベースに適用されている状況です。

マイグレーションファイルも実行済み

最後にデータベースを確認してみましょう。

以下のようにschema_migrationsテーブルには、実行済みのマイグレーションのバージョンが挿入されます。データベースにはemployeesテーブルも作成されていますね。

schema_migrationsテーブル

ロールバックの注意点

すでに学習した内容ですが、マイグレーションファイルはrails db:migrateで一度実行すると、再度実行できない仕組みになっています。

この仕組みは、個別のマイグレーションファイルを変更履歴として残し、「どのような変更が行われてきたか」を確認したり、過去のある状態に戻れるようにするためです。

マイグレーションファイルの履歴

ロールバックでは、マイグレーションを過去のバージョンに戻すことができます。ロールバックで修正を行う際、ケアレスミスなどの軽度な修正でも状況を見極める必要があります。

もし、チーム開発で共同作業者に影響が出る(masterにmergeしている)状況や本番環境でマイグレーションファイルが実行済みであれば、ロールバックで既存のマイグレーションファイルを直接変更してはいけません。

この状況では、ロールバックで既存のマイグレーションを直接修正するのではなく、影響を小さく抑えるために修正用のマイグレーションファイルを新たに作成する必要があります。

ぴっかちゃん

masterにmergeしたマイグレーションファイルや本番環境で実行済みのマイグレーションファイルは変更しちゃダメってことだね!

その通りだよ。さっそくマイグレーションファイルの作成方法を学んでみよう!

ぴかわかさん

7-2.新しいマイグレーションファイルの作成方法

マイグレーションファイルは、モデルと併せて作成する以外にも、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」になります。

例 | 20xxxxxxxxxxxx_add_age_to_users.rbを作成
1
rails generate migration AddAgeToUsers
例 | 20xxxxxxxxxxxx_add_age_to_users.rb
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

上記のコマンドを実行すると、以下のようなマイグレーションファイルが自動で生成されます。

例 | 20xxxxxxxxxxxx_add_age_to_users.rb
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」と指定します。

例 | usersテーブルにageカラムを追加する場合
1
rails generate migration AddAgeToUsers

上記のコマンドを実行すると、以下のようにファイル名の後半と一致するクラス名のマイグレーションファイルが作成されます。クラス内には、changeメソッドが定義されます。

例 | 20xxxxxxxxxxxx_add_age_to_users.rb
1
2
3
4
class AddAgeToUsers < ActiveRecord::Migration[6.1]
  def change
  end
end

テーブルにカラムを追加する場合、changeメソッド内でadd_columnメソッドを利用します。以下のように追加するカラムを定義することができます。例ではusersテーブルに追加するageカラムに対して、INT型、非NULL制約を設定しています。

例 | add_columnメソッドの基本書式
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テーブルにageカラムを追加してみよう

それでは、マイグレーションファイルを作成して、employeesテーブルにINT型のageカラムを追加してみましょう。以下のコマンドを順番に実行してください。

employee_managementディレクトリへ移動する
1
cd ~/environment/employee_management
~/environment/employee_management | マイグレーションファイルを生成する
1
rails g migration AddAgeToEmployees

上記のコマンドを実行すると、以下のようにdb/migrateディレクトリにマイグレーションファイルが作成されます。※ タイムスタンプ値は一致する必要はありません。

マイグレーションファイル作成

作成したマイグレーションファイルを開いて、ageカラムを定義してみよう

まずは、db/migrateディレクトリ内にあるマイグレーションファイルを開きましょう。

作成したマイグレーションファイル

以下のようにadd_columnメソッドを利用して、追加するageカラムを定義しましょう。

db/migrate/20xxxxxxxxxxxxxx_add_age_to_employees.rb
1
2
3
4
5
class AddAgeToEmployees < ActiveRecord::Migration[6.1]
  def change
add_column :employees, :age, :integer
end end
マイグレーションの状況を確認してみよう

現時点では、マイグレーションファイルに追加するカラムを定義しただけなので、データベースに適用していない状況です。rails db:migrate:statusコマンドを実行して、 作成したマイグレーションファイルのStatusdownであることを確認しましょう。

~/environment/employee_management | マイグレーションの状況を確認する
1
rails db:migrate:status

マイグレーションの状況

マイグレーションファイルを実行しよう

それでは、rails db:migrateコマンドを利用して、未実行のマイグレーションファイルを実行させて、データベースに適用させましょう。

~/environment/employee_management | 未実行のマイグレーションファイルを実行させる
1
rails db:migrate

上記のコマンドを実行すると、以下のようにマイグレーションファイルが実行されます。

未実行のマイグレーションファイルを実行させる

続いて、以下のようにrails db:migrate:statusコマンドを実行して、 作成したマイグレーションファイルのStatusupであることを確認しましょう。

~/environment/employee_management | マイグレーションの状況を確認する
1
rails db:migrate:status

マイグレーションの状況を確認する

employeesテーブルにageカラムが追加されたかをデータベースで確かめてみましょう

最後にphpMyAdminにログインして、employeesテーブルにageカラムが追加されていることを確認しましょう。

データベースを確認する

テーブルからのカラム削除方法

テーブルからカラムを削除する場合は、rails generate migrationで指定する「クラス名」を「Removeカラム名Fromテーブル名」にします。

基本書式
1
rails generate migration クラス名
テーブルからカラムを削除する場合
1
rails generate migration Removeカラム名Fromテーブル名

例えばusersテーブルからageカラムを削除する場合、以下のようにクラス名を「RemoveAgeFromUsers」と指定します。

例 | usersテーブルからageカラムを削除する場合
1
rails generate migration RemoveAgeFromUsers

上記のコマンドを実行すると、以下のようにファイル名の後半と一致するクラス名のマイグレーションファイルが作成されます。クラス内には、changeメソッドが定義されます。

例 | 20xxxxxxxxxxxx_remove_age_from_users.rb
1
2
3
4
class RemoveAgeFromUsers < ActiveRecord::Migration[6.1]
  def change
  end
end

テーブルからカラムを削除する場合、changeメソッド内でremove_columnメソッドを利用します。以下のように削除するカラムを定義することができます。例ではusersテーブルから削除するカラムとして、INT型、非NULL制約が設定されるageカラムを定義しています。

例 | 20xxxxxxxxxxxx_remove_age_from_users.rb
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テーブルからageカラムを削除してみよう

それでは、マイグレーションファイルを作成して、employeesテーブルからINT型のageカラムを削除してみましょう。以下のコマンドを順番に実行してください。

employee_managementディレクトリへ移動する
1
cd ~/environment/employee_management
~/environment/employee_management | マイグレーションファイルを生成する
1
rails g migration RemoveAgeFromEmployees

上記のコマンドを実行すると、以下のようにdb/migrateディレクトリにマイグレーションファイルが作成されます。※ タイムスタンプ値は一致する必要はありません。

マイグレーションファイル作成

作成したマイグレーションファイルを開いて、削除するageカラムを定義してみよう

まずは、db/migrateディレクトリ内にあるマイグレーションファイルを開きましょう。

作成したマイグレーションファイル

以下のようにremove_columnメソッドを利用して、削除するageカラムを定義しましょう。

db/migrate/20xxxxxxxxxxxxxx_remove_age_from_employees.rb
1
2
3
4
5
class RemoveAgeFromEmployees < ActiveRecord::Migration[6.1]
  def change
remove_column :employees, :age, :integer
end end
マイグレーションの状況を確認してみよう

現時点では、マイグレーションファイルに削除するカラムを定義しただけなので、データベースに適用していない状況です。rails db:migrate:statusコマンドを実行して、 作成したマイグレーションファイルのStatusdownであることを確認しましょう。

~/environment/employee_management | マイグレーションの状況を確認する
1
rails db:migrate:status

マイグレーションの状況

マイグレーションファイルを実行しよう

それでは、rails db:migrateコマンドを利用して、未実行のマイグレーションファイルを実行させて、データベースに適用させましょう。

~/environment/employee_management | 未実行のマイグレーションファイルを実行させる
1
rails db:migrate

上記のコマンドを実行すると、以下のようにマイグレーションファイルが実行されます。

未実行のマイグレーションファイルを実行させる

続いて、以下のようにrails db:migrate:statusコマンドを実行して、 作成したマイグレーションファイルのStatusupであることを確認しましょう。

~/environment/employee_management | マイグレーションの状況を確認する
1
rails db:migrate:status

マイグレーションの状況を確認する

employeesテーブルからageカラムが削除されているかを確かめてみましょう

最後にphpMyAdminにログインして、employeesテーブルからageカラムが削除されていることを確認しましょう。

データベースを確認する

この章のまとめ

この章では、Railsにおけるデータベース操作の基本的な概念と手法について学びました。
MVCアーキテクチャにおけるデータベースとのやり取りの流れを学び、モデルの基本概念とActiveRecordの重要性について理解を深めました。また、マイグレーションの基礎から実践を通して、実際にRailsでデータベースを管理する方法を学びました。

この章を通じて、Railsにおけるデータベースの操作方法と管理の基本を習得し、実際にRailsアプリケーションでデータベースを効率的に扱うための基盤を築くことができました。

この章をもう一度学習したい方のみ、以下のコマンドを実行して環境をリセットし、改めて「1.Railsでのデータベース操作の理解」から取り組んでみてください。

アプリケーションのルートディレクトリに移動しましょう
ターミナル
1
cd ~/employee_management
モデルとデータベースを削除し、データベースを作成しなおしましょう

アプリケーションのルートディレクトリで以下のコマンドを実行して、EmployeeモデルとDepartmentモデル、データベースを削除して、再度データベースを作成しなおしましょう。

ターミナル(~/employee_management)
1
rails d model employee && rails d model department && rails db:drop && rails db:create
不要なマイグレーションファイルを作成しましょう
ターミナル(~/employee_management)
1
rm -rf db/migrate

この章のまとめ

  • マイグレーションとは、データベースの構造を作成、変更および削除できる仕組みのこと
  • マイグレーションはバージョン管理を行うので、実行したマイグレーションファイルは削除してはいけない!