Skip to content

Instantly share code, notes, and snippets.

@harlow
Last active November 16, 2023 15:13
Show Gist options
  • Save harlow/5368275 to your computer and use it in GitHub Desktop.
Save harlow/5368275 to your computer and use it in GitHub Desktop.
Extract a validator in Rails. Zip code validation.
# app/models/user.rb
class User < ActiveRecord::Base
validates :zip_code, presence: true, zip_code: true
end
# app/validators/zip_code_validator.rb
class ZipCodeValidator < ActiveModel::EachValidator
ZIP_CODE_REGEX = /^\d{5}(-\d{4})?$/
def validate_each(record, attribute, value)
unless ZIP_CODE_REGEX.match value
record.errors.add(attribute, "#{value} is not a valid zip code")
end
end
end
# spec/validators/zip_code_validator_spec.rb
require 'spec_helper'
describe ZipCodeValidator, '#validate_each' do
it 'does not add errors with a valid zip code' do
record = build_record('93108')
ZipCodeValidator.new(attributes: :zip_code).validate(record)
record.errors.should be_empty
end
it 'adds errors with an invalid zip code' do
record = build_record('invalid_zip')
ZipCodeValidator.new(attributes: :zip_code).validate(record)
record.errors.full_messages.should eq [
'Zip code invalid_zip is not a valid zip code'
]
end
def build_record(zip_code)
test_class.new.tap do |object|
object.zip_code = zip_code
end
end
def test_class
Class.new do
include ActiveModel::Validations
attr_accessor :zip_code
def self.name
'TestClass'
end
end
end
end
@dgilperez
Copy link

Hi!

Thanks for sharing :)

I'm generalizing the Validator to support different countries. Check it out if you want: https://gist.github.com/dgilperez/6232901

Cheers!

@scottbartell
Copy link

You should use \A and \z as anchors in your regex. http://stackoverflow.com/a/3632051

@dgilperez
Copy link

Hey!

I ended up pulling some bits together into this gem: validates_zipcode.

It currently supports 159 countries zipcode formats and plays nice with Rails 3 & 4.

You can use it like this:

class Address < ActiveRecord::Base
  validates_zipcode :zipcode
  validates :zipcode, zipcode: true
  validates :zipcode, zipcode: { country_code: :ru }
  validates :zipcode, zipcode: { country_code_attribute: :my_zipcode }
end

Cheers!

@ACPK
Copy link

ACPK commented Dec 3, 2015

@dgilperez @harlow - This validator doesn't seem to work if you're using "presence: false". I might recommend using "unless PHONE_REGEX.match(value) || value.blank?" so that a developer can use the presence attribute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment