require 'open-uri' require 'cgi' require 'rexml/document' # Defined by the ISO 3166-2 standard. This is a standard that gives short codes # for provinces, etc. within a country. class Region < ActiveRecord::Base # The url of the open source version of the ISO 3166-2 standard ISO_3166_2_URL = 'http://svn.debian.org/wsvn/pkg-isocodes/trunk/iso-codes/iso_3166/iso_3166_2/iso_3166_2.xml?op=file' class << self # Creates a fixtures containing all possible regions def create_fixtures(output_file_path = nil) output_file_path ||= 'db/bootstrap/regions.yml' output_file_path = File.join(RAILS_ROOT, output_file_path) FileUtils.mkdir_p(File.dirname(output_file_path)) output_file = File.new(output_file_path, File::CREAT|File::TRUNC|File::RDWR) output = '' regions = download_all puts "Saving regions to #{output_file_path}..." if PluginAWeek::Has::Addresses.verbose regions.each do |region| record_name = region.name.gsub(' ', '_').gsub(/[^A-Za-z_]/, '').downcase output << "#{record_name}:\n" region.attributes.each do |attr, value| output << " #{attr}: #{value}\n" if value end end output_file << output.slice(0..output.length-2) output_file.close puts 'Done!' if PluginAWeek::Has::Addresses.verbose true end # Bootstraps the table by downloading the latest ISO 3166-2 standard and # saving each region to the database def bootstrap regions = download_all puts 'Loading regions into database...' if PluginAWeek::Has::Addresses.verbose delete_all regions.each {|region| region.save!} puts 'Done!' if PluginAWeek::Has::Addresses.verbose true end # Downloads the latest ISO 3166-2 standard and returns the data as a list of # regions def download_all countries = Country.download_all alpha_2_code_to_country = Hash[*countries.collect {|c| [c.alpha_2_code, c]}.flatten] # Download the standard puts 'Downloading ISO 3166-2 data...' if PluginAWeek::Has::Addresses.verbose iso_3166_2 = open(ISO_3166_2_URL).readlines * "\n" iso_3166_2 = CGI::unescapeHTML(/
(.+)<\/pre>/im.match(iso_3166_2)[1].gsub(' ', '')) # Parse and load the regions puts 'Parsing regions...' if PluginAWeek::Has::Addresses.verbose region_id = 1 regions = [] REXML::Document.new(iso_3166_2).elements.each('*/iso_3166_country') do |country| code = country.attributes['code'][0..1] # Belarius is more than 2 characters for some reason, so just get the first 2 country_record = alpha_2_code_to_country[code.upcase] country.elements.each('iso_3166_2_entry') do |region| name = region.attributes['name'].to_s.gsub("'","\\'").strip abbreviation = region.attributes['code'].upcase.sub("#{code}-", '') region = new( :country_id => country_record.id, :name => name, :abbreviation => abbreviation ) region.id = region_id if !country_record.regions.any? {|known_region| known_region.name == region.name} regions << region country_record.regions << region region_id += 1 end end end regions end end belongs_to :country has_many :addresses validates_presence_of :name, :country_id, :abbreviation validates_length_of :name, :within => 2..80 validates_length_of :abbreviation, :within => 1..5 validates_uniqueness_of :name, :scope => :country_id validates_uniqueness_of :abbreviation, :scope => :country_id def to_s #:nodoc name end end