Custom Validators

As an exercise, I created a simple custom validator. I had done this before at work, but I had managed to forget how to do it between then and now. I guess that’s why I need a bit of extra practice :)

So the idea is that, instead of including this ugly regex in the model, you can pull it out (or whatever you are using to validate your attribute) and put it in a separate validator class. It makes the model much simpler and makes it so it is no longer responsible for the logic behind the validation.

If you are using Rails, you would just put PhoneValidator within the validators folder and it will find it without requiring it in the model as I do here.

# person.rb

require 'phone_validator'

class Person
  include ActiveModel::Validations

  validates :phone_number, phone: true

  attr_accessor :phone_number

  def initialize(attributes = {})
    @phone_number = attributes[:phone_number]
  end
end

# phone_validator.rb

class PhoneValidator < ActiveModel::EachValidator
  PHONE_REGEX ||= /^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$/

  def validate_each(record, attribute, value)
    unless value =~ PHONE_REGEX
      record.errors[attribute] = "invalid phone number formatting" 
    end
  end
end