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

Railsで個別のカラムをバリデーションするvalidate_specific_value gem

More than 1 year has passed since last update.

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

参考リンク

validate_specific_value gem

ts-3156
公開している記事のうち、私が集計まで担当しているものは、希望があれば元データをお渡しいたします。ご希望される方は、Twitterでご連絡ください。
https://twitter.com/ts_3156
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