これは何?
RailsガイドのActive Recordの基礎が理解をする上で非常によかったので、
振り返れるようにまとめます。
Active Recordって何?
MVCのM、つまりモデルに相当するもので、Active Recordを介してデータベースとやりとりができます。
なお、データベースとやりとりをする時の考え方として、ORM(オブジェクトリレーショナルマッピング)を採用しており、
モデルをインスタンス化したオブジェクトと、MySQLのようなRDBを接続することで様々なことを直接SQL文を書かずに実現しています。
Active Recordの機能
- モデルおよびモデル内のデータを表現する
- モデル間の関連付け(アソシエーション)を表現する
- 関連するモデルを介した継承階層を表現する
- データがデータベースに永続的に保存される前に検証(validation)を行なう
- オブジェクト指向の表記方法でデータベースを操作する
覚えるべきルール
モデルクラスってどこまで何やってるの?
例えば、
bundle exec rails generate model User name:string email:string
でモデルクラスを作成するとします。
(その後、bundle exec rails db:migrate
とかはやっておいてください)
class User < ApplicationRecord
end
上記のようなモデルクラスが作成されますが、これがどこまで何をやってるかというと、
- Userモデルとusersテーブルの関連付け。
- usersテーブルの各カラムをUserモデルのインスタンスの属性に関連付け。
をやっています。
そのため、上記のコードだけでもいきなり、
user = User.new(name:"test", email:"test@gmail.com")
user.name = "Jiggaman"
user.save
user1 = User.find_by(name:"Jiggaman")
user1.destroy
みたいに直接DBを触って出し入れしたりすることができてしまうのです。
バリデーション
モデルではDBに保存される前にValidationをかけることができます。
基本的には、インスタンスを生成するコントローラーにて、
- create
- save
- update
がされる前にモデルに定義されているValidationを通り、有効な場合のみにDBに保存されるという流れとなります。
なお、Validationを通らずにスキップしてしまうメソッドもあるため、全てがValidationを通ると思わないように注意してください。
save
をするタイミングでValidationエラーとなると、
errors.messages
を返します。
そのため、下記のように設定することが可能となります。
class User < ApplicationRecord
validates :name, presence: true
end
def create
user = User.new
if user.save
# DBに保存成功
else
# DBに保存失敗
user.errors.full_messages.each do |error|
puts error
end
end
end
今回の場合、name
カラムが空欄のままDBに保存しようとしているため、validation
にかかってerrorとなります。
なお、:message
オプションを使用することで、バリデーション失敗時のエラーメッセージをカスタマイズすることができます。
validates :name, presence: { message: "must be given" }
バリデーションヘルパー
こちらから下記のヘルパーそれぞれの説明を確認可能です。
- acceptance
- validates_associated
- confirmation
- exclusion
- format
- inclusion
- length
- numericality
- presence
- absence
- uniqueness
- validates_with
- validates_each
コールバック
Validates
がDBに保存する直前に動作するものだったのに対し、
コールバックは、オブジェクトの状態が切り替わる「前」or「後」で動作します。
オブジェクトの状態が切り替わるタイミングとは、
オブジェクトが作成/保存/更新/削除/検証/DBからの読み込みなどです。
下記が基礎的なコールバックです。
class User < ApplicationRecord
# createメソッドのタイミングだけ事前にnormalize_nameメソッドが走ります
before_validation :normalize_name, on: :create
# create, update両方のタイミングで事後にset_locationメソッドが走ります
after_validation :set_location, on: [ :create, :update ]
# 下記のように事前に呼び出すメソッドの内容をブロックで表現することも可能です
before_create do
self.name = login.capitalize if name.blank?
end
# コールバックメソッドはprivateで宣言してください
private
def normalize_name
self.name = name.downcase.titleize
end
def set_location
self.location = LocationService.query(self)
end
end
もう少し詳細な利用可能なコールバックと順番はこちらを参照してください。
アソシエーション
モデルとモデルを関連づけることによって、はるかに簡単な操作で実現したいことができるようになりますので是非知っておいてください。
効果を実感できない方は、こちらの例を見ることでそのバグツンの効果を実感できると思います。