Skip to content

Instantly share code, notes, and snippets.

@dgilperez
Forked from harlow/user.rb
Last active December 21, 2015 02:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dgilperez/6232901 to your computer and use it in GitHub Desktop.
Save dgilperez/6232901 to your computer and use it in GitHub Desktop.
# app/models/user.rb
class User < ActiveRecord::Base
validates :zipcode, presence: true, zipcode: true
end
# lib/validators/zipcode_validator.rb
# Usage:
#
# class User << AR
# validates :postalcode, zipcode: true
#
# # Required country_alpha2 attribute
# def country_alpha2
# country.alpha2
# end
# end
#
class ZipcodeValidator < ActiveModel::EachValidator
# using country alpha2 code as key
ZIPCODES_REGEX = {
ES: /\A\d{5}\z/,
AR: /\A([A-HJ-TP-Z]{1}\d{4}[A-Z]{3}|[a-z]{1}\d{4}[a-hj-tp-z]{3})\z/,
NZ: /\A\d{4}\z/,
AU: /\A\d{4}\z/,
US: /\A\d{5}(-\d{4})?\z/,
CA: /\A[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTWVXYZ]\d[ABCEGHJKLMNPRSTWVXYZ]\d\z/
}
def validate_each(record, attribute, value)
alpha2 = record.country_alpha2.try(:to_sym)
unless alpha2 && ZIPCODES_REGEX[alpha2].match(value)
record.errors.add(attribute, "#{value} is not a valid zipcode")
end
end
end
# spec/lib/validators/zipcode_validator_spec.rb
require 'spec_helper'
describe ZipcodeValidator, '#validate_each' do
context "Spain" do
it 'does not add errors with a valid zipcode' do
record = build_record('93108', "ES")
zipcode_should_be_valid(record)
end
it 'adds errors with an invalid Zipcode' do
['1234', '12345-12345', 'D0D0D0', 'invalid_zip'].each do |zipcode|
record = build_record(zipcode, 'ES')
zipcode_should_be_invalid(record, zipcode)
end
end
end
context "USA" do
it 'does not add errors with a valid zipcode' do
record = build_record('93108', "US")
zipcode_should_be_valid(record)
['12345', '12345-1234'].each do |zipcode|
record = build_record(zipcode, 'US')
zipcode_should_be_valid(record)
end
end
it 'adds errors with an invalid Zipcode' do
['1234', '12345-12345', 'D0D0D0', 'invalid_zip'].each do |zipcode|
record = build_record(zipcode, 'US')
zipcode_should_be_invalid(record, zipcode)
end
end
end
context "Argentina" do
it 'does not add errors with a valid zipcode' do
record = build_record('C1424CHN', "AR")
zipcode_should_be_valid(record)
end
it 'adds errors with an invalid Zipcode' do
['1234', '12345', 'D0D0D0', 'invalid_zip'].each do |zipcode|
record = build_record(zipcode, 'AR')
zipcode_should_be_invalid(record, zipcode)
end
end
end
context "Australia and New Zeland" do
it 'does not add errors with a valid zipcode' do
["AU", "NZ"].each do |code|
record = build_record('9310', code)
zipcode_should_be_valid(record)
end
end
it 'adds errors with an invalid Zipcode' do
["AU", "NZ"].each do |code|
['C1424CHN', '12345', 'invalid_zip'].each do |zipcode|
record = build_record(zipcode, code)
zipcode_should_be_invalid(record, zipcode)
end
end
end
end
context "Canada" do
it 'does not add errors with a valid zipcode' do
record = build_record('A1J2Z9', 'CA')
zipcode_should_be_valid(record)
end
it 'adds errors with an invalid Zipcode' do
['C1424CHN', '12345', 'D0D0D0', 'invalid_zip'].each do |zipcode|
record = build_record(zipcode, 'CA')
zipcode_should_be_invalid(record, zipcode)
end
end
end
def zipcode_should_be_valid(record)
ZipcodeValidator.new(attributes: :zipcode).validate(record)
record.errors.should be_empty
end
def zipcode_should_be_invalid(record, zipcode = "invalid_zip")
ZipcodeValidator.new(attributes: :zipcode).validate(record)
record.errors.full_messages.should eq [
"Zipcode #{zipcode} is not a valid zipcode"
]
end
def build_record(zipcode, country_alpha2)
test_class.new.tap do |object|
object.country_alpha2 = country_alpha2
object.zipcode = zipcode
end
end
def test_class
Class.new do
include ActiveModel::Validations
attr_accessor :zipcode, :country_alpha2
def self.name
'TestClass'
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment