RailsのActiveRecordで個別のカラムをバリデーションするvalidate_specific_value gemを作った。
このgemを使う利点
通常のバリデーション実行にはmodel#valid?
を使うが、このメソッドはそのモデルのすべてのバリデーションを実行してしまう。
バリデーションの内容によってはデータベースでSQLを実行するもの、複雑なRubyのコードを実行するもの、などがあり、毎回すべてのバリデーションを実行してしまうと必要以上にコストがかかってしまうことになる。
app/models/user.rb
class User < ApplicationRecord
# valid?を呼ぶたびに、emailとnameがユニークかどうかをチェックするSQLを実行する
validates :email, uniqueness: true
validates :name, uniqueness: true
# valid?を呼ぶたびに、高コストなバリデーションが実行される
validates_with Validations::ComplexValidator
end
このvalidate_specific_value gemを使えば、特定のカラムだけに対してバリデーションを実行することができる。
validate_specific_value gemの使い方
Gemfileに追加する。
Gemfile
gem 'validate_specific_value'
validates_specific
で個別にバリデーションしたいカラムを指定する。
app/models/user.rb
class User < ApplicationRecord
validates_specific :name
end
validates_specific :attribute
としておくことで、valid_attribute?
というメソッドが定義される。
user = User.new(name: 'duplicate_name')
user.valid_name?
# => false
user.errors[:name]
# => ["has already been taken"]
実装の詳細
メタプログラミングで下記の処理を実現している。RailsのAPIで特定のカラムのバリデーションルールをすべて取得し、それをループの中で実行している。
class User < ApplicationRecord
def valid_name?
errors.clear
self.class.validators_on(:name).each do |validator|
validator.validate_each(self, :name, self[:name])
end
errors.empty?
end
end