33日目 初期データベース設定②(migrationファイルの各行の説明)

おはようございます。昨日の記事の続きですが、今日の作業はなく、説明のみとなります。

おさらい

昨日、以下のモデル1~3を構成するためのコマンドを入力し、Railsアプリケーションにおけるmodelファイルとmigrationファイルを作成しました。

・モデル1:Room ⇒ カラム(型):ID(int)
・モデル2:User ⇒ カラム(型):ID(int)、name(string)
・モデル3:Comment ⇒ カラム(型):ID(int)、content(string)、created_at(datetime)

それぞれのモデル1~3を生成する(moderlファイルとmigrationファイルを自動生成する)コマンドは以下の通りです。

モデル1生成コマンド

jruby -S bundle _1.17.3_ exec rails generate model Room

モデル2生成コマンド

jruby -S bundle _1.17.3_ exec rails generate model User name:string

モデル3生成コマンド

jruby -S bundle _1.17.3_ exec rails generate model Comment content:string

【お詫びとご注意】
申し訳ありません。上記のコマンドですが、末尾の「content:string」は修正済のもので、元々、修正前は「name:content」となっておりました。(本当は「string」型にしたかったけれども、「content」型という存在しないものを指定してしまっていました。)

昨日の記事を見ていただいて、既にコマンド入力済の方は、お手数をおかけいたしますが、以下の2つのコマンドを上から順に入力すれば、モデル3のmodelファイルとmigrationファイルの修正をやり直すことができます。

jruby -S bundle _1.17.3_ exec rails destroy model Comment
jruby -S bundle _1.17.3_ exec rails generate model Comment content:string

昨日の記事を見ていただいたからは、上記のご注意を踏まえたうえで、以降を見ていただきましたら幸いです…。


上記3つのコマンド入力後、Visual Studio Codeを起動して、Railsアプリケーションのプロジェクトデータが配置されている場所を開き、Visual Studio Codeの画面左側「エクスプローラー」ビューから「app」⇒「migrate」の順にクリックしてみてください。

以下のように
「(YYYYMMDDhhmmss)_create_rooms.rb」←モデル1生成コマンドから生成
「(YYYYMMDDhhmmss)_create_users.rb」←モデル2生成コマンドから生成
「(YYYYMMDDhhmmss)_create_comments.rb」←モデル3生成コマンドから生成
という3つのファイルがあると思います。
※(YYYYMMDDhhmmss)は年月日を表します。
※コマンド入力では「Room」「User」「Comment」で単数形だったものが、ファイル名には「rooms」「users」「comments」と複数形となっておりますが、Railsの規約により、自動的に複数形となります。
(データベースを扱うときは、同じモデル(≒クラス)に対して複数のインスタンス(1つのインスタンス = データベースの1レコード)を生成して、同時に複数扱うことになるため、複数形になるという考え方かと思います。)

今日は、これらのコマンドを入力してできたmigrationファイルについての説明と、migrationファイルを用いたデータベース(開発環境)への反映について説明します。

モデル1「Room」を生成するコマンドを入力して自動的に作成された「(YYYYMMDDhhmmss)_create_rooms.rb」のファイルの中身は以下の通りとなっております。

1 class CreateRooms < ActiveRecord::Migration
2   def change
3     create_table :rooms do |t|
4 
5       t.timestamps null: false
6     end
7   end
8 end

「Room」モデルを例としたmigrationファイルの中身の説明

「(YYYYMMDDhhmmss)_create_rooms.rb」のファイル(「Room」モデルのmigrationファイル)の中身について、それぞれの行の意味について順番に説明します。なお、4行目は何も記述されていないため、その行の説明は飛ばします。

1行目:class CreateRooms < ActiveRecord::Migration

1行目の「class CreateRooms < ActiveRecord::Migration」は
「ActiveRecord::Migration」を継承する「CreateRooms」のクラスを定義する行の始まり』
を示します。

「ActiveRecord::Migration」って何だろう?と思う方もいると思いますが、「Migration」(マイグレーション)は「移行」「移転」「移動」という意味があり、Railsにおいては、Railsのモデルの中身を定義したものをデータベースのテーブルへと「移行」ということになります。

なぜ「Migration」という言葉を使うのかというと、データベースのテーブルを新しく作成するためにはSQL文を使用する必要があるのですが、Railsの「ActiveRecord::Migration」クラスは、開発者が作成したいデータベースのテーブルの定義内容をRubyの書き方・Railsの規約に基づいたソースコードで記載することによって、定義内容を自動的にSQL文へと変換することができます。

そのため、開発者はSQL文を考える必要がなく、Railsが代わりにSQL文の作成を行なってくれるため、Rubyの書き方・Railsの規約に基づいて記載したソースコードをSQL文へと「移行」する、ということから、「Migration」という言葉を使います。(以下、参考となる記事を載せます)

それで、1行目の説明へ改めて話を戻すと、1行目の「CreateRooms」クラスは、「ActiveRecord::Migration」から機能を継承されていますが、「ActiveRecord::Migration」はデータベースのテーブルの定義内容をSQL文へと変換する機能を持っているので、機能が継承されている「CreateRooms」クラスもSQL文へと変換することが可能です。

というわけで、1行目の説明だけで長くなってしまいましたが、「class CreateRooms < ActiveRecord::Migration」というのは、SQL文への変換機能を持つ「CreateRooms」が「Room」モデルをデータベースのテーブルへと反映するための行の始まりとも認識していただけましたら幸いです。

2行目:def change

次の2行目の「def change」については、
『「change」というメソッドの行の始まり』
を示します。
「def」とは、英語の「definition」の頭3文字を取ったものであり、「change」は「変更」という意味ですので、「def change」はデータベースをどのように変更するのか、その動きの始まりとも言えます。

3行目:create_table :rooms do |t|

続いて3行目、「create_table :rooms do |t|」ですが、「create_table :rooms」という部分は、
『「Rooms」というデータベースのテーブルの新規作成の始まり』
を示します。

そして、その後の「do |t|」というのは、ちょっと長いですが、
『「Rooms」というデータベースのテーブルが作られたとして、そのテーブルから1つのレコードが生成される場合、レコードを構成するカラムの定義は何か?』
という行の始まりを示しており、もう一つ、『カラムを定義する際の1レコードは仮に「t」とします。』という意味も付加されています。

5行目:t.timestamps null: false

そして5行目は、
『仮のレコード「t」において、タイムスタンプに関連する2つのカラム「created_at」(作成時刻)、「updated_at」(更新時刻)があり、そしてそれらのカラムはnullを許可しない(必ず何かしらの値を入れる必要がある)設定とする』
という意味になります。そのため、1つのレコードが生成されると、「created_at」という作成時刻を表すカラムと「updated_at」という更新時刻を表すカラムに必ず値が入ることになります。

なお、Railsにおいては「created_at」には、1つのレコードが新規で生成されたときの時刻が値として入り、「updated_at」には最初は「created_at」と同様に1つのレコードが生成された時刻が入りますが、その後、そのレコードに対して何らかの変更があった場合は、変更したときの時刻が「update_at」の値へと自動的に上書きすることになります。
※どちらもRailsにおいては、「datetime」という型で値が入るようです。

6~8行目:end

最後に、6~8行目にそれぞれ「end」がありますが、その前の行で始めたもの終わりが「end」で対応しています。

「end」と対応する始まりはその「end」から上へ昇る順に最も近いところに対応しますので、6行目の「end」は、3行目の「create_table :rooms do |t|」と対応します。つまり、3~6行目が、『「Rooms」というデータベースのテーブルの新規作成』を定義する部分になります。

また、7行目の「end」についても対応する始まりを下から上へと探していくと、3行目の始まりは先ほど説明したように6行目の終わりと対応するので、3行目を飛ばすと、2行目の「def change」と対応することになります。つまり2~7行目が、『「change」というメソッド』を定義する部分となり、データベースをどのように変更するのかは、2~7行目を見ればわかるということになります。

そして、8行目の「end」と対応する始まりも、6・7行目と同様に下から上へと探していくと、3行目、2行目を飛ばして最初の1行目の「class CreateRooms < ActiveRecord::Migration」と対応します。つまり、1行目~8行目が『「ActiveRecord::Migration」を継承する「CreateRooms」のクラス』を定義する部分となります。

補足:IDカラムの自動付加について

ちなみに、データベースの1つのテーブルを新規生成(create)する際のmigrationファイルには、「ID」というカラムを定義するコードが記載されていなかったとしても、自動的に定義されることになります。

自動で定義された「ID」は主キー(プライマリーキー)となり、他のレコードと一意で区別するものになり、また、1つのレコードが生成されるたびに、1つのIDが自動的に連番で割り当てられます。(例:1,2,3,4,5,…)

なお、指定すれば主キーを「ID」から別のカラムへと変更できるようですが、よほどのことがない限りはそういうことはないかと思います。

以上が、「Room」モデルを例としたmigrationファイルの中身の説明となります。

他のmigrationファイルの場合

他にも2つ、「User」モデルと「Comment」モデルのmigrationファイルもありますが、それらも少しだけ説明します。

「User」モデルにおいてデータベースのテーブルを定義するmigrationファイル(「(YYYYMMDDhhmmss)_create_users.rb」)の中身は以下の通りです。

1 class CreateUsers < ActiveRecord::Migration
2   def change
3     create_table :users do |t|
4       t.string :name
5
6       t.timestamps null: false
7     end
8   end
9 end

各行の意味は、先ほど説明した「Room」モデルとほぼ同じ意味ですが、4行目のみ「Room」モデルにはないものがあります。

4行目は、
『仮のレコード「t」において、「name」というカラム名があり、そしてその値の型を「string」とする』
という意味になります。この行を書くことによって「User」モデルには「string」型の「name」という名前を持つカラムが定義されます。

「Comment」モデルの場合も見てみます。「Comment」モデルのデータベースのテーブルを定義するmigrationファイル(「(YYYYMMDDhhmmss)_create_comments.rb」)の中身は以下の通りです。

1 class CreateComments < ActiveRecord::Migration
2   def change
3     create_table :comments do |t|
4       t.string :content
5
6       t.timestamps null: false
7     end
8   end
9 end

こちらの「Comment」モデルのmigrationファイルの各行の意味も、先ほど説明した「Room」モデルとほぼ同じ意味ですが、4行目のみ「Room」モデルにはないものがあります。

4行目は、
『仮のレコード「t」において、「content」というカラム名があり、そしてその値の型を「string」とする』
という意味になります。この行を書くことによって「User」モデルには「string」型の「content」という名前を持つカラムが定義されます。

おわりに

ここまで読んでくださってありがとうございました。
昨日書いて公開した記事に誤りが見つかったため、その修正に時間取られたりしましたが、なんとか終わらせることができてよかったです…^^;

次回も続きます。

この記事が気に入ったらサポートをしてみませんか?