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"]
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