Home > Mobile >  using the same validator for different attributes Rails
using the same validator for different attributes Rails

Time:01-10

I have a custom validator that I want to apply to several attributes in the same model

right now I the following the works just fine:

 validates :first_name, validator_name: true
 validates :age, validator_name: true
 validates :gender, validator_name: true

But when I try:

validates :first_name, :age, :gender, validator_name: true

The validator will run for the first attribute (:first_name) but not the others. Is this possible to achieve? I spent hours googling this but haven't found any examples

module Person
  class SomeValidator < ActiveModel::EachValidator

    def validate_each(record, attribute, value)
      return unless can_do_something?(record, attribute)

      #... more code 
    end

   def can_do_something?(record, attribute)
      anything_new = record.new_record? || record.attribute_changed?(attribute)
   end
  end
end

CodePudding user response:

Not sure if this should just be a comment or if it constitutes an answer; however what you are requesting...

I have a custom validator that I want to apply to several attributes in the same model

...is how an EachValidator works.

So what you are describing...

The validator will run for the first attribute (:first_name) but not the others.

..cannot be accurate.

For Example:

require 'active_model'
class StartsWithXValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value.match?(/^(?:\d \s|^)X/)
      record.errors.add attribute, "must start with X"
    end
  end
end

class Person
  include ActiveModel::Model
  include ActiveModel::Validations
  
  attr_accessor :name, :city, :street
  
  validates :name, :city, :street, starts_with_x: true
end

In this case all three attributes will be validated through the StartsWithXValidator.

e.g.

person = Person.new({name: 'Xavier', city: 'Xenia', street: '123 Xenial St'})
person.valid? 
#=> true

person_2 = Person.new({name: 'Benjamin', city: 'Philadelphia', street: '700 Market St'})
person_2.valid? 
#=> false
person_2.errors.full_messages 
#=> ["Name must start with X", "City must start with X", "Street must start with X"]

Working Example

CodePudding user response:

I think you can use a custom method validation:

  validate :validate_person

  def validate_person
    [:first_name, :age, :gender].each do |attr|
      validates attr, validator_name: true
    end
  end

Reference: https://guides.rubyonrails.org/active_record_validations.html#custom-methods

  • Related