Permalink
Browse files

add postal code validator

  • Loading branch information...
1 parent 965a4d7 commit dc9d39a837adcfb63ccd0e92afde4b29d3bc8fb0 @cap10morgan cap10morgan committed Mar 8, 2012
@@ -0,0 +1,44 @@
+validates_as_postal_code
+=====================
+
+Strict validation module for postal and zip codes.
+
+= General usage
+
+== Installation
+
+You can install the plugin the traditional way. Go to your application root
+and do:
+
+ script/plugin install git://github.com/paulschreiber/validates_as_postal_code.git
+
+== Validate your model attributes
+
+Example:
+
+There are three ways to specify the country:
+ (1) Pass the country name in as a string parameter (:country => "CA")
+ class Person < ActiveRecord::Base
+ validates_as_postal_code :postal_code, :country => "CA", :allow_blank => true
+ end
+
+ (2) Create an attribute (country field) named foo in your object, and pass in a reference to foo:
+ class Person < ActiveRecord::Base
+ validates_as_postal_code :postal_code, :country => :foo
+ end
+
+ (3) Create an attribute named country it in your object, i.e. Person#country
+ i.e. country is the default name for your country field, and the validator tries that automatically
+
+ class Person < ActiveRecord::Base
+ validates_as_postal_code :postal_code
+ end
+
+The :set parameter tells the validator to reformat the postal_code number (change punctuation and spacing) in to a standard format.
+
+Supported countries are Canada (CA), the United States (US), Australia (AU), New Zealand (NZ). :set only works for Canada and the US; it's ignored for other countries.
+
+
+= License
+
+Copyright (c) 2010 Paul Schreiber, released under the MIT license
@@ -0,0 +1,89 @@
+module ValidationKit
+ class PostalCodeValidator < ActiveModel::EachValidator
+
+ def postal_code_regex_for_country(country_code)
+ if country_code.blank?
+ nil
+ elsif ["AU", "NZ"].include?(country_code)
+ /\d{4}/
+ elsif ["US"].include?(country_code)
+ /\d{5}(-\d{4})?/
+ elsif ["CA"].include?(country_code)
+ /[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTWVXYZ]\d[ABCEGHJKLMNPRSTWVXYZ]\d/
+ else
+ nil
+ end
+ end
+
+ def disallowed_characters_for_country(country_code)
+ if country_code.blank?
+ nil
+ elsif ["US", "AU", "NZ"].include?(country_code)
+ /[^0-9]/
+ elsif ["CA", "UK"].include?(country_code)
+ /[^0-9A-Z]/
+ else
+ nil
+ end
+ end
+
+ def validate_each(record, attribute, value)
+ if options[:country].is_a?(String)
+ country = options[:country]
+ elsif options[:country].is_a?(Symbol) and record.respond_to?(options[:country])
+ country = record.send(options[:country])
+ elsif record.respond_to?(:country)
+ country = record.send(:country)
+ else
+ country = false
+ end
+
+ next unless country
+ current_regex = postal_code_regex_for_country(country)
+ next unless current_regex
+ disallowed_characters = disallowed_characters_for_country(country)
+
+ new_value = value.nil? ? "" : value.upcase.gsub(disallowed_characters, '')
+
+ unless (options[:allow_blank] && new_value.blank?) || new_value =~ current_regex
+ message = I18n.t("activerecord.errors.models.#{name.underscore}.attributes.#{attribute}.invalid",
+ :default => [:"activerecord.errors.models.#{name.underscore}.invalid",
+ options[:message],
+ :'activerecord.errors.messages.invalid'])
+ record.errors[attribute] << message
+ else
+ record.send(attr_name.to_s + '=',
+ format_as_postal_code(new_value, country, disallowed_characters)
+ ) if options[:set]
+ end
+ end
+
+ def format_as_postal_code(arg, country_code, disallowed_characters)
+ return nil if (arg.blank? or country_code.blank? or !postal_code_regex_for_country(country_code))
+
+ postal_code = arg.gsub(disallowed_characters, '')
+
+ if ["US"].include?(country_code)
+ digit_count = postal_code.length
+ if digit_count == 5
+ return postal_code
+ elsif digit_count == 9
+ return "%s-%s" % [postal_code[0..4], postal_code[5..8]]
+ else
+ return nil
+ end
+
+ elsif ["AU", "NZ"].include?(country_code)
+ postal_code
+
+ elsif ["CA"].include?(country_code)
+ fsa = postal_code[0..2]
+ lda = postal_code[3..5]
+
+ postal_code = "%s %s" % [fsa, lda]
+ postal_code.upcase
+ end
+ end
+ end
+ end
+end

0 comments on commit dc9d39a

Please sign in to comment.