Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

この記事では、 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 の使い分けを知らないとプチハマりする。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした