motolog

Everything I love in my life.

Rails - mockを使って1つの属性のみにvalidationを走らせてみる

ユニークなユーザー名やサブドメインを付与するときに、ajaxで入力されたその場で有効な値かどうかを判断してあげれば、ユーザビリティは向上するだろう。ツイッターなど大規模なウェブサービスでは実装されていることが多いかと思う。

しかし、.valid? メソッドを使ってしまうと、そのオブジェクト全体にvalidationがかかってしまい不都合が生じてしまうので、今回は、1つの属性に対してvalidationをする方法について扱う。

具体的には、以下のように、検証を行いたい1つの属性を持った新しいオブジェクト(ここでは、mock)を作り、mock.valid? でエラーを発生させ、そのエラーに調べたい属性のkeyがあるかどうかを見る。

def valid_attribute?(attr, value, present_username)
  mock = User.new(attr => value)
  unless mock.valid?
    if mock.errors.has_key?(attr) && value != present_username
      return false
    else
      return true
    end
  end
  true
end

attr が調べたい属性の名前、value がその属性に与えられた値。
さらに、ここでは、ユーザーネームの検証を行うと仮定して、present_username という引数を与えてみた。

ポイントは、

mock = User.new(attr => value)

で、ユーザーが入力した値を用いて、新しいユーザー mock を擬似的につくり、

unless mock.valid?

で、エラーを発生させ(全ての属性の検証にクリアすれば true が返る)、

if mock.errors.has_key?(attr) && value != present_username

で、エラーに attr という key があり、かつ、入力された値 value が現在のユーザーネーム present_username と異なる、という条件で value が不正な条件を作り出している点。

個人的に、mock をつくるのと、errors.has_key? を使うあたり、勉強になった。

色んな方法があるのだなーと。

参考にしたのは、stackoverflow の以下の記事。
Is there a way to validate a specific attribute on an ActiveRecord without instantiating an object first?

また、ActiveRecord を使用している場合は、以下の記事で触れられている方法が使えそう。
Rails - 状況によってsave時に実行するバリデーションを切り替える


view側の実装は別記事にする予定。

© 2018 Motoki Yoshida