7. モデル¶
7.1. モデルの作り方¶
モデルを作るには、 rails generate scaffold
か rails generate model
のどちらかを使う。
model
はモデルだけを作り、scaffold
はモデルだけでなくビューやコントローラも一揃い作ってくれる。ビューやコントローラは別に作ることもできるし、作っておいて使わなくてもいいので、どちらにするかはあまり悩まくてもよい。モデルの名前は単数形の名詞が推奨されている。(命名ルール)
モデルは関係データベースのテーブルと対応している。テーブルの構成を「カラム名:型」という形式でモデル名の後に書く。この型はRubyの型ではなくデータベースの型。よく使われる型は次の通り。
整数
integer
浮動小数点数
float
文字列
string
時刻
datetime
真偽値
boolean
どのモデルにも
id
というカラムが必ず存在するが、書かなくても自動的に作られる。他のモデルを参照するカラムは、
モデル名_id:integer
にするのがお約束。(スキーマのルール)
ここでは、 Student
を scaffold
で、 Faculty
を model
で作ってみる。
# rails generate scaffold student name:string faculty_id:integer
# rails generate model faculty name:string
7.2. データベースのマイグレーション¶
rails generate scaffold
または rails generate model
をやった段階では、まだデータベースは出来ていない。データベースに指示を出すためのRubyファイル(マイグレーションファイル)が出来ている。それは db/migrate
の下にある。
# ls db/migrate
20181029094006_create_students.rb 20181029094021_create_faculties.rb
これを実行して、データベースの中にテーブルを作ることをマイグレーションと呼ぶ。 rails db:migrate
は、まだ実行されていないマイグレーションファイルを実行する(マイグレーションを実行する)。
# rails db:migrate
7.3. モデルの変更¶
学生のモデル Student
には、氏名と学部のカラムしか無いので、学年のカラムを追加する。
7.3.1. お行儀の良いやり方¶
変更用のマイグレーションファイルを作る。こうすると、データベースの変更履歴がマイグレーションファイルの形で記録されるので、後で再現できる。
rails generate migration
(マイグレーションを作成する) を使うと自動的にマイグレーションファイルを作ってくれる。
項目を追加する時は Add項目Toモデル
という名前にし、その後に項目名と型を書く。例えば、学生のモデルに学年という項目を追加したいときは次のようにする。
# rails generate migration AddGradeToStudents grade:integer
# rails db:migrate
データベースを前の状態に戻したいときは、 rails db:rollback
(ロールバック) を行う。今は CreateStudents, CreateFaculties, AddGradeToStudents
の3個のマイグレーションファイルを実行した状態だが、ロールバックするごとに一段階ずつ前の状態に戻っていく。
# rails db:rollback
# rails db:rollback
# rails db:rollback
これで何もマイグレーションしていない状態になった。もう一度 rails db:migrate
を実行すると、マイグレーションされていないファイルを一気に処理する。
# rails db:migrate
7.3.2. お行儀のよろしくないやり方¶
複数人で開発する場合や、すでに本番サーバでシステムが動いている場合は、データベースの変更を差分として管理することが必要だが、一人で新規開発しているのなら気にする必要はない。だいたい開発中の試行錯誤の履歴を残しておいても恥ずかしいだけである。
開発中は、マイグレーションファイルの中に書いてある項目名や型を直接修正し、データベースをぶっ壊してもう一度最初からマイグレーションをやり直せばよい。
例えば、 Student
モデルのマイグレーションファイルは db/migrate/バージョン番号_create_studetns.rb
という名前で、次のような内容になっている。
class CreateStudents < ActiveRecord::Migration[7.2]
def change
create_table :students do |t|
t.string :name
t.integer :faculty_id
t.timestamps
end
end
end
学年を追加したければ、 t.string :name
などと並列に t.integer :grade
という行を書き込む。
データベースを一回白紙に戻してから全部作りなおすのは
# rails db:migrate:reset
とする。運用中のシステムでこれをやると、データベースに入っているデータが全部消えてしまうので注意。
7.4. モデルのクラス¶
それぞれのモデルごとにクラスが定義される。これは app/models
の下にある。クラス定義の中身は空っぽだが、データベースにアクセスするメソッドは動的に生成されるので大丈夫。
# ls app/models
application_record.rb faculty.rb
concerns student.rb
rails console
を使うと、テストやデバッグのために、このファイルを読み込んだ状態で、対話的にRubyを実行することができる。
注釈
日本語が文字化けする場合は、 rails console
を実行する前に export LANG=C.UTF-8
を実行しておく。
例えば、総合政策学部のデータを作ってみよう。
# rails console
irb(main):001:0> x = Faculty.new(name: '総合政策')
irb(main):002:0> x.save
irb(main):003:0> x.id
Faculty
クラスのインスタンスを新しく作り、学部名(カラム名はname
)を設定する。name: '総合政策'
はキーが:name
で値が'総合政策'
のハッシュ。できたインスタンスに対して
save
メソッドを呼び出すと、インスタンスの情報がデータベースに保存される。その時にデータベースを管理するための項目id, created_at, update_at
などが自動的に設定される。id
は、Railsが勝手に1から順につけていく。
データベースに保存されたデータを取り出すには、次のようなメソッドを使う。
id
が1番の学部のデータが欲しい時は、Faculty.find(1)
を呼び出すと、Faculty
のインスタンスが返ってくる。すべての学部のデータが欲しい時は、
Faculty.all
を呼び出すと、Faculty
のインスタンスの配列が返ってくる(正確にはActiveRecord::Relation
のインスタンスだけれど、まあ配列と思って使っても大丈夫)。
条件を指定して検索するやり方は次の次の次の週ぐらいにやる。
課題11
科目を表すモデル Course
を作り、次のようなデータを登録せよ。ただし、後の都合があるので、 rails generate model
を使い、コントローラとビューは作らないこと。
id |
name |
credit |
compulsory |
---|---|---|---|
1 |
体育1 |
1 |
true |
2 |
プログラミング言語論 |
2 |
false |
ターミナルの実行経過をSFC-SFSに貼り付けて提出。
【解答例】
7.5. モデルの対応関係¶
各モデルのデータの間には、一対一、一対多、多対多の関係がある場合がある。例えば、学部と学生の関係は一対多になる。Railsではそういう関係を宣言しておくと、いろいろと便利になる(Active Record の関連付け)。
例として、総合政策学部の太郎のデータを作ってみよう。総合政策学部の id
は1なので、太郎の faculty_id
の値は1にする。
irb(main):004:0> y = Student.new(name: '太郎', faculty_id: 1)
irb(main):005:0> y.save
カラムの値は、例えば太郎の学年は y.grade
と書ける。太郎が1年生であるとすると、 y.grade = 1
で設定できる。その後に save
するのを忘れないように。
irb(main):006:0> y.grade = 1
irb(main):007:0> y.save
太郎の学部を調べたい時は、 faculty_id
の値が1なので総合政策学部に所属することがわかる。しかし、 faculty_id
の値を見て、その番号の学部を探すというのは面倒なので、学生のインスタンスからすぐに学部のインスタンスが得られるようにしたい。そのためには、学生のクラス app/models/student.rb
に belogns_to
を追加する。モデル名はシンボルで指定することに注意。
class Student < ApplicationRecord
belongs_to :faculty
end
すると、 Student
クラスに faculty
メソッドが(Railsによって勝手に)追加される。これを呼び出すと、その学生に対応する Faculty
クラスのインスタンスが得られる。
rails console
を終了し(コントロールD)、エディタで app/models/student.rb
を修正・保存した後、もう一度 rails console
を実行する。
# rails console
irb(main):001:0> x = Student.find(1)
irb(main):002:0> x.faculty
逆に、学部のインスタンスからその学部に所属する学生のインスタンス(複数個ある)を得たい時は、 app/models/faculty.rb
に has_many
を追加する。この場合はモデル名を複数形にする約束になっている(単数形でもたぶん動く)。
class Faculty < ApplicationRecord
has_many :students
end
そうすると Faculty
クラスに students
というメソッドが出来て、その学部に所属している学生全員の配列を得ることができる。
# rails console
irb(main):001:0> x = Faculty.find(1)
irb(main):002:0> x.students
課題12
環境情報学部のデータと、花子と一郎は環境情報学部の学生であるということをデータベースに登録し、環境情報学部のインスタンスに対して students
メソッドを呼び出すと、二人のデータが出てくることを確認せよ。ターミナルの実行経過をSFC-SFSに貼り付けて提出。
【解答例】