LoginSignup
30
22

More than 5 years have passed since last update.

【決定版】Railsで個別の属性を検証するカスタムバリデーションを作る

Last updated at Posted at 2017-11-28

この記事では、 ActiveModel::EachValidator を使った、個別の項目を検証するバリデータの作り方を基礎から応用まで解説します:shield:

:beginner:基礎

まずRailsガイドを読んでみましょう。

個別の属性を検証するためのカスタムバリデータを追加するには、ActiveModel::EachValidatorを使用するのが最も簡単で便利です。この場合、このカスタムバリデータクラスはvalidate_eachメソッドを実装する必要があります。このメソッドは、そのインスタンスに対応する「レコードと属性と値」、バリデーションを行なう属性、そして渡されたインスタンスの属性の値の3つの引数を取ります。

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
      record.errors[attribute] << (options[:message] || "はメールアドレスではありません")
    end
  end
end

class Person < ActiveRecord::Base
  validates :email, presence: true, email: true
end

上の例に示したように、標準のバリデーションとカスタムバリデーションを組み合わせることもできます。

とあります。

補足です:bulb:。たしかにこれで動くのは動くとは思いますが、バリデータは app/validators/email_validator.rb とかに入れ、モデルには

app/models/model_name.rb
validates :field_name, email: true

など、2つを分けて書くのが普通だと思います。補足終わりです:smile:

なるほどなるほど、 email: true のようなバリデータはこの知識だけで作れますが、 true だけではすまないバリデータ、すなわち、 inclusion: ['01', '02'] や、オプションも指定した numericality: { only_integer: true } のようなバリデータは実装できません。

では、応用編です。

:muscle: 応用

オプションありパターン

では理解しやすい、オプションありパターンからいきましょう。 numericality: { only_integer: true } のように Hash つきで呼び出すと、 { only_integer: true } は(引数にありませんが) options で取れます。つまり、 only_integer の値が取りたければ、 options[:only_integer] を呼ぶことになります。

Railsガイドの例でも options[:message] と書いてある部分があり、

validates :field_name, email: { message: 'を正しく入力してください' }

のように書く機能も備えていたことになります。

オプションなしパターン

では、 Hash なし、すなわち、 inclusion: ['01', '02'] のような呼び出しパターンでは、与えられた ['01', '02'] の部分はどう受け取ればよいのでしょうか。これ、さらっと探したけどあまり説明がなく、Railsのソースを見てたどり着きました。結論は、

['01', '02'] の部分が、:

  • Range or Array の場合、 options[:in] で、
  • 上記以外の場合、 options[:with]

取ります:astonished:

えーー! ハッシュの値に指定した型によって、取り方が変わるの?? あっ、でも確かに、オプションの有無によって、

validates :field_name, format: /\A[a-zA-Z]+\z/
validates :field_name, format: { with: /\A[a-zA-Z]+\z/, message: "英文字のみが使用できます" }

validates :field_name, inclusion: %w(small medium large)
validates :field_name, inclusion: { in: %w(small medium large), message: "%{value} のサイズは無効です" }

のように、 inwith が(自然と)使い分けられているのを見たことがある方は多いのではないでしょうか。それはこういうことだったのか……。

まとめ

Railsのバリデータを自作するときは inwith の使い分けを知らないとプチハマりする。

30
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
22