I'm working on learning custom validations in rails and am attempting to apply it for the purpose of comparing two form fields. So far, I can easily pass one value to the custom my custom validator which I've stored in app/validation/pin_validator.rb
and it works fine. But I'd really like to set up something like the following that would accept two pieces of data from the form:
class PinValidator < ActiveModel::EachValidator
def validate_each (record, attribute, value)
if value1 > value2
record.errors[attribute] << (options[:message] || "validator working")
end
end
end
And call it from the model with something like this:
validates :pin_number, :id_string, pin: true
Where :id_string
and :pin_number
are both form fields and would be compared as value1
and value2
Is there a way to do this?
Many thanks in advance!
Note: The value comparison above really could be solved on the front-end with a little javascript. The reason I'm asking for a serverside solution is that I ultimately intend to compare both values with a set of entries in the database. The example above is just to distil my question to something simple.
You should be able to access attributes listed with @attributes
inside the validate_each
method, as you can infer from the initializer code here
So you can access record
attributes by using values from @attributes
which is an array with the attribute names used on the definition of the validation, in your case [:pin_number, :id_string]
. You can access them like
def validate_each(record, attribute, value)
value1 = record[@attributes[0]] # :pin_number
value2 = record[@attributes[1]] # :id_string
# the rest of the logic here
end
I realize the validate_each
method is going to be run twice as it is supposed to run for each of the fields listed on the validation definition. That might lead to errors being inserted twice or other issues. I am researching if the validator instance is created every time a validation is to be run, if so you could avoid this double validation by setting up a flag, say @already_run
and then just returning if that flag was true the second time. As a new instance of the validator would be created next time anything needed to be validated then the flag wouldn't affect anything else.