Using a custom validator to compare two form fields


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

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

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.