Railsで特定のコントローラーからバリデーションを制御する
目次
フリーランスでシステムエンジニアしております。
Active Record バリデーションについての備忘録です。
- 特定の条件下で使いたい
save
している箇所から使用するバリデーションを制御したい
if等を使用した条件付きバリデーション
:ifや:unlessでシンボルを使う
バリデーションの実行直前に呼び出されるメソッド名を、:if
や:unless
オプションにシンボルで指定することもできます。 これは最もよく使われるオプションです。
class Order < ApplicationRecord
validates :card_number, presence: true, if: :paid_with_card?
def paid_with_card?
payment_type == "card"
end
end
条件付きバリデーションをグループ化する
1つの条件を複数のバリデーションで共用できると便利なことがあります。これはwith_options
で簡単に実現できます。
class User < ApplicationRecord
with_options if: :is_admin? do |admin|
admin.validates :password, length: { minimum: 10 }
admin.validates :email, presence: true
end
end
with_options
ブロックの内側にあるすべてのバリデーションにif: :is_admin?
という条件が渡されます。
onを使用した条件分岐
:on
オプションは、バリデーション実行のタイミングを指定します。
create, update
on: :create
を指定すればレコード新規作成時にのみバリデーションが行われ、on: :update
を指定すればレコードの更新時にのみバリデーションが行われます。
class Person < ApplicationRecord
# 値が重複していてもemailを更新できる
validates :email, uniqueness: true, on: :create
# 新規レコード作成時に、数字でない年齢表現を使える
validates :age, numericality: true, on: :update
# デフォルト (作成時と更新時の両方でバリデーションを行なう)
validates :name, presence: true
end
カスタムコンテキスト
on:
にはカスタムコンテキストも定義できます。カスタムコンテキストは、valid?
やinvalid?
やsave
にコンテキスト名を渡して明示的にトリガーする必要があります。
class Person < ApplicationRecord
with_options on: :account_setup do
validates :email, uniqueness: true
validates :age, numericality: true
end
end
valid?
は以下のようにします。(モデルを保存せずにバリデーションを2つとも実行します)
person.valid?(:account_setup)
save
は以下のように指定します。(保存の前にaccount_setupコンテキストでpersonを検証します)
person.save(context: :account_setup)
update
はcontextオプションは使えない
update
で同じことをやりたい場合は、attributesにセットしてからsaveメソッドを使えばできます。
person.update(update_params)
上記を以下のようにします。
person.attributes = update_params
person.save(context: :account_setup)
RSpec
be_valid
使うときはコンテキスト名を渡します
expect(person).to be_valid :account_setup
エラーメッセージの確認は、始めにvalid?
します。
person.valid?(:account_setup)
expect(person.errors[:email]).to be_present
まとめ
:if
オプションは「特定の条件を満たす場合にのみバリデーションを実行したい場合」に使います。主にモデルの状態から判定します。- カスタムコンテキスト(
:on
) は便利な機能です。これを使うと使用している箇所から制御できますね。👍
参考サイト
Railsガイド