参考書を読んだメモ : 独習Ruby on Rails 6章

独習Ruby on Rails

モデルに実装すべき役割

バリデーション(検証)

  • フォームなどから入力されたデータが妥当かどうか評価し、適正なデータだけをデータベースに取り込むための機能
  • 入力データのチェック

バリデーションの実装場所

  • データベースの情報はモデルを通してテーブルへ登録されるのでモデルにするのが自然
  • モデルによって検証された適正なデータだけがテーブルに登録されるべき
  • ActiveRecordにはバリデーションを実装するためのメソッドが用意されている

バリデーション評価のタイミング

  • データベスのテーブルを更新するメソッドを呼び出したときに自動的に実行される(create/save/update)
    • save/update はバリデーションエラー時にfalseを返す
    • create はエラーとなったインスタンスを返す
    • これらの後ろに!をつけたメソッドは例外を返す
  • バリデーション無視するときは save(validate: false) と指定できる
  • valid?
    • 任意のタイミングでバリデーションを評価するメソッド
    • 真偽逆の値を返すのは invalid?
    • データ登録前の確認フェーズなどに使える
  • バリデーション評価の結果に対するエラー情報は、バリデーション評価メソッドを実行したレシーバーに組み込まれ、そのインスタンスに対するerrorメソッドで確認できる

標準バリデーションヘルパー

  • presence/absence
    • 値が存在する/空である ことを検証する
  validates :title, presence: true
  • length
    • 文字の長さが妥当であるかを検証する
  validates :description, length: { maximum: 100 }
  • numericality
    • 数値であるかや、数値の範囲が妥当であるかなどを検証する
    • only_integer
      • 整数であるか
    • odd
      • 奇数であるか
    • even
      • 偶数であるか
    • greater_than
      • > で指定された値より大きいか
    • less_than
      • < で指定された値より小さいか
    • equal_to
      • = で指定された値と等しいか
    • greater_than_or_equal_to
      • >=
    • less_than_or_equal_to
      • <=
  validates :height, numericality: { greater_than: 0 }
  • format
    • 文字列が正規表現に一致するかどうか検証する
  validates :postal_code, format: { with: /\A\d{3}-\d{4}\z/ }
  • confirmation
    • 2つの入力内容が等しいかを検証する
    • #{attribute}_confirmation に入力された時に比較する
    • 利用するためには「attr_accesor :#{attribute}_confirmation」のように設定する必要がある
  validates :password, confirmation: true
  • inclusion/exvlusion
    • 文字列が配列に含まれている/含まれていないかを検証する
  • acceptance
  • uniqueness
    • 値がユニークであることを検証する
  • validates_associated
    • 関連づいているモデルに対してバリデーションを一括に行う場合に使用する
class Product < ApplicationRecord
  has_many :parts
  validates_associated :parts
end 

バリデーションオプション

  • allow_nil
    • true で nil 許容
  validates :name, presence: true, allow_nil: true
  • allow_blank
    • 空を許容
  • message
    • エラーメッセージを指定
    • 指定しない場合はデフォルトのメッセージを表示
  • on
    • バリデーションの実行対象を指定「on: create」など(デフォルトでは create/save/update時に実行)
  • if/unless
    • バリデーションの実行条件を指定
  • 独自メソッドを作ることも可能

コールバック機能

コールバックとは

  • 検証、作成、保存、更新、削除のイベントタイミングで、特定の処理を呼び出し実行させる機能
  • before_validation/after_validation
    • バリデーションの直前/直後に指定されたメソッドを呼び出す
  before_validation :normalize_name
  • before_(save/update/create/destroy)
    • それぞれのイベントの直前に指定されたメソッドを呼び出す
  • around_(save/update/create/destroy)
    • それぞれのイベントの前後に指定されたメソッドを呼び出す
  • after_(save/update/create/destroy)
    • それぞれのイベントの直後に指定されたメソッドを呼び出す
  • 複数のコールバックも指定できる

その他のコールバック

  • after_initialize/after_found
    • データリソースのインスタンス化ごと/取得するごとに指定されたメソッドを呼び出す
  • after_touch
    • 対象のモデルオブジェクトの touch メソッドが実行されるごとに指定されたメソッドを呼び出す
  • after_create_commit/after_update_commit/after_destroy_commit
    • モデルに対するデータベース変更のコミットが完了した時に指定されたメソッドを呼び出す
  • after_rollback

スコープ

  • スコープはモデルに対してよく利用する検索条件を用意しメソッドとして使うことができる機能

スコープの例

class モデル名 < ApplicationRecord
  scope :メソッド名, -> { 検索条件 } 
  scope :メソッド名, -> (引数) { 検索条件 }
  scope :target_area, -> (dist){ where("distance <= ?",  dist) }
end
  • それぞれのスコープはメソッドチェーンとして結合して利用できる

デフォルトスコープ

  • モデルを呼び出す際に、あらかじめ用意されたスコープが常に実行される仕組み
  default_scope { where("price <= 500") }
  • デフォルトスコープを無視する際は、unscoped メソッドを使う
  Product.unscoped.all

ロック機能

  • lock_version というモデルに用意された属性がある
  • lock_version は、モデルを通して処理されるリソースに対して同時にアクセスがあった時に、更新の整合性を確保するために利用される属性

楽観的ロック機能

  • 不整合を防止するために、データを読み込んだ時のバージョンと更新する時のバージョンを比較して、異なっていた場合例外エラーを発生させる
  • 更新されるたびに lock_version が1ずつ増加し更新の有無を管理できる

悲観的ロック機能

  • データを取得する時点で他が読めないようにロックをかけ、完全な整合性を確保する方法