us_zipcode 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.travis.yml +19 -0
  4. data/Gemfile +21 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.textile +179 -0
  7. data/README.textile~ +184 -0
  8. data/Rakefile +19 -0
  9. data/features/step_definitions/common_steps.rb +76 -0
  10. data/features/step_definitions/rails_setup_steps.rb +17 -0
  11. data/features/step_definitions/rails_setup_steps.rb~ +17 -0
  12. data/features/support/env.rb +10 -0
  13. data/features/support/string.rb +128 -0
  14. data/features/zipcodes.feature +24 -0
  15. data/features/zipcodes.feature~ +24 -0
  16. data/lib/generators/us_zipcode/models_generator.rb +41 -0
  17. data/lib/generators/us_zipcode/models_generator.rb~ +41 -0
  18. data/lib/generators/us_zipcode/templates/county_model.rb +17 -0
  19. data/lib/generators/us_zipcode/templates/county_model.rb~ +17 -0
  20. data/lib/generators/us_zipcode/templates/migration.rb +41 -0
  21. data/lib/generators/us_zipcode/templates/migration.rb~ +41 -0
  22. data/lib/generators/us_zipcode/templates/state_model.rb +15 -0
  23. data/lib/generators/us_zipcode/templates/state_model.rb~ +15 -0
  24. data/lib/generators/us_zipcode/templates/zipcode_model.rb +30 -0
  25. data/lib/generators/us_zipcode/templates/zipcode_model.rb~ +30 -0
  26. data/lib/generators/us_zipcode/templates/zipcodes.rake +163 -0
  27. data/lib/generators/us_zipcode/templates/zipcodes.rake~ +163 -0
  28. data/lib/generators/us_zipcode/version.rb +3 -0
  29. data/lib/generators/us_zipcode/version.rb~ +3 -0
  30. data/lib/my_zipcode_gem.rb~ +34 -0
  31. data/lib/us_zipcode.rb +29 -0
  32. data/lib/us_zipcode.rb~ +29 -0
  33. data/rails3_2.gemfile +21 -0
  34. data/rails4_0.gemfile +23 -0
  35. data/rails4_1.gemfile +23 -0
  36. data/us_zipcode.gemspec +24 -0
  37. data/us_zipcode.gemspec~ +24 -0
  38. metadata +108 -0
@@ -0,0 +1,128 @@
1
+ class String
2
+
3
+ class << self
4
+ def random(count = 6, ranges = [('a'..'z'),('A'..'Z'),('0'..'9')])
5
+ o = ranges.map{|i| i.to_a}.flatten;
6
+ string = (0..(count-1)).map{ o[rand(o.length)] }.join;
7
+ end
8
+ end
9
+
10
+ def left(count)
11
+ self.slice(0,count)
12
+ end
13
+
14
+ def right(count)
15
+ self.slice(-count,count)
16
+ end
17
+
18
+ def left_trim
19
+ # remove leading whitespace
20
+ self.gsub(/^[\t\s]+/, '')
21
+ end
22
+
23
+ def right_trim
24
+ # remove trailing whitespace
25
+ self.gsub(/[\t\s]+$/, '')
26
+ end
27
+
28
+ def trim
29
+ # remove leading and trailing whitespace
30
+ self.left_trim.right_trim
31
+ end
32
+
33
+ # html = <<-stop.here_with_pipe
34
+ # |<!-- Begin: comment -->
35
+ # |<script type="text/javascript">
36
+ # stop
37
+ def here_with_pipe(linefeeds = false)
38
+ lines = self.split("\n")
39
+ lines.map! {|c| c.sub!(/\s*\|/, '')}
40
+ new_string = lines.join(linefeeds ? "\n" : " ")
41
+ self.replace(new_string)
42
+ end
43
+
44
+ def is_alpha_numeric?
45
+ regex = /^[a-zA-Z0-9]+$/
46
+ return (self =~ regex) == 0 ? true : false
47
+ end
48
+
49
+ def is_email_address?
50
+ # //Email address
51
+ # //Use this version to seek out email addresses in random documents and texts.
52
+ # //Does not match email addresses using an IP address instead of a domain name.
53
+ # //Does not match email addresses on new-fangled top-level domains with more than 4 letters such as .museum.
54
+ # //Including these increases the risk of false positives when applying the regex to random documents.
55
+ # '\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b'
56
+ #
57
+ # //Email address (anchored)
58
+ # //Use this anchored version to check if a valid email address was entered.
59
+ # //Does not match email addresses using an IP address instead of a domain name.
60
+ # //Does not match email addresses on new-fangled top-level domains with more than 4 letters such as .museum.
61
+ # //Requires the "case insensitive" option to be ON.
62
+ # '^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$'
63
+ #
64
+ # //Email address (anchored; no consecutive dots)
65
+ # //Use this anchored version to check if a valid email address was entered.
66
+ # //Improves on the original email address regex by excluding addresses with consecutive dots such as john@aol...com
67
+ # //Does not match email addresses using an IP address instead of a domain name.
68
+ # //Does not match email addresses on new-fangled top-level domains with more than 4 letters such as .museum.
69
+ # //Including these increases the risk of false positives when applying the regex to random documents.
70
+ # '^[A-Z0-9._%-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$'
71
+ #
72
+ # //Email address (no consecutive dots)
73
+ # //Use this version to seek out email addresses in random documents and texts.
74
+ # //Improves on the original email address regex by excluding addresses with consecutive dots such as john@aol...com
75
+ # //Does not match email addresses using an IP address instead of a domain name.
76
+ # //Does not match email addresses on new-fangled top-level domains with more than 4 letters such as .museum.
77
+ # //Including these increases the risk of false positives when applying the regex to random documents.
78
+ # '\b[A-Z0-9._%-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}\b'
79
+ #
80
+ # //Email address (specific TLDs)
81
+ # //Does not match email addresses using an IP address instead of a domain name.
82
+ # //Matches all country code top level domains, and specific common top level domains.
83
+ # '^[A-Z0-9._%-]+@[A-Z0-9.-]+\.(?:[A-Z]{2}|com|org|net|biz|info|name|aero|biz|info|jobs|museum|name)$'
84
+ #
85
+ # //Email address: Replace with HTML link
86
+ # '\b(?:mailto:)?([A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4})\b'
87
+
88
+ email_regex = %r{^[A-Z0-9._%-]+@[A-Z0-9.-]+\.(?:[A-Z]{2}|com|org|net|biz|info|name|aero|biz|info|jobs|museum|name)$}xi # Case insensitive
89
+
90
+ return (self =~ email_regex) == 0 ? true : false
91
+ end
92
+
93
+ def is_zipcode?
94
+ self =~ %r{^(\d{5})(-\d{4})?$}x ? true : false
95
+ end
96
+
97
+ def format_phone
98
+ '(' << slice(0..2) << ')' << slice(3..5) << '-' << slice(-4,4)
99
+ end
100
+
101
+ def is_numeric?
102
+ begin
103
+ Float(self)
104
+ rescue
105
+ false # not numeric
106
+ else
107
+ true # numeric
108
+ end
109
+ end
110
+
111
+ def sanitize
112
+ clean_string = self.gsub(/[^a-z0-9,! \-\(\)\:\;\.\&\$]+/i, '')
113
+ #p "SAN: #{clean_string}"
114
+ clean_string
115
+ end
116
+
117
+ def shorten(count = 30)
118
+ if self.length >= count
119
+ shortened = self[0, count]
120
+ splitted = shortened.split(/\s/)
121
+ words = splitted.length
122
+ splitted[0, words-1].join(" ") + ' ...'
123
+ else
124
+ self
125
+ end
126
+ end
127
+
128
+ end
@@ -0,0 +1,24 @@
1
+ Feature: Us ZipCode Gem
2
+ In order to manage zipcode resources
3
+ As a rails developer
4
+ I want to generate models for zipcode, county and state, and populate their tables
5
+
6
+ Scenario: Generate models and migration for zipcode, county and state
7
+ Given a new Rails app
8
+ Then I should see "us_zipcode:models" when running "rails g"
9
+ When I run "rails g us_zipcode:models"
10
+ Then I should see the following files
11
+ | app/models/zipcode.rb |
12
+ | app/models/state.rb |
13
+ | app/models/county.rb |
14
+ | lib/tasks/zipcodes.rake |
15
+ | db/migrate |
16
+ And I should see "gem "mocha"" in file "Gemfile"
17
+ And I should successfully run "rake db:migrate"
18
+
19
+ Scenario: Update data for zipcodes, counties and states tables
20
+ Given a new migrated Rails app
21
+ Then I should successfully run "rake zipcodes:update"
22
+ And I should see 51 records in the "states" table
23
+ And I should see 3142 records in the "counties" table
24
+ And I should see 42366 records in the "zipcodes" table
@@ -0,0 +1,24 @@
1
+ Feature: My Zipcode Gem
2
+ In order to manage zipcode resources
3
+ As a rails developer
4
+ I want to generate models for zipcode, county and state, and populate their tables
5
+
6
+ Scenario: Generate models and migration for zipcode, county and state
7
+ Given a new Rails app
8
+ Then I should see "my_zipcode_gem:models" when running "rails g"
9
+ When I run "rails g my_zipcode_gem:models"
10
+ Then I should see the following files
11
+ | app/models/zipcode.rb |
12
+ | app/models/state.rb |
13
+ | app/models/county.rb |
14
+ | lib/tasks/zipcodes.rake |
15
+ | db/migrate |
16
+ And I should see "gem "mocha"" in file "Gemfile"
17
+ And I should successfully run "rake db:migrate"
18
+
19
+ Scenario: Update data for zipcodes, counties and states tables
20
+ Given a new migrated Rails app
21
+ Then I should successfully run "rake zipcodes:update"
22
+ And I should see 51 records in the "states" table
23
+ And I should see 3142 records in the "counties" table
24
+ And I should see 42366 records in the "zipcodes" table
@@ -0,0 +1,41 @@
1
+ module UsZipcode
2
+ class ModelsGenerator < Base
3
+ include Rails::Generators::Migration
4
+
5
+ source_root File.expand_path('../templates', __FILE__)
6
+
7
+ def initialize(*args, &block)
8
+ super
9
+ migration_template 'migration.rb', "db/migrate/create_us_zipcode_models.rb"
10
+ end
11
+
12
+ def generate_models
13
+ # puts ">>> generate_zipcodes:"
14
+ end
15
+
16
+ def add_gems
17
+ add_gem "mocha", :group => :test
18
+ end
19
+
20
+ def create_models
21
+ template 'zipcode_model.rb', "app/models/zipcode.rb"
22
+ template 'county_model.rb', "app/models/county.rb"
23
+ template 'state_model.rb', "app/models/state.rb"
24
+ end
25
+
26
+ # Implement the required interface for Rails::Generators::Migration.
27
+ # taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
28
+ def self.next_migration_number(dirname)
29
+ if ActiveRecord::Base.timestamped_migrations
30
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
31
+ else
32
+ "%.3d" % (current_migration_number(dirname) + 1)
33
+ end
34
+ end
35
+
36
+ def create_rakefile
37
+ template 'zipcodes.rake', "lib/tasks/zipcodes.rake"
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ module MyZipcodeGem
2
+ class ModelsGenerator < Base
3
+ include Rails::Generators::Migration
4
+
5
+ source_root File.expand_path('../templates', __FILE__)
6
+
7
+ def initialize(*args, &block)
8
+ super
9
+ migration_template 'migration.rb', "db/migrate/create_my_zipcode_gem_models.rb"
10
+ end
11
+
12
+ def generate_models
13
+ # puts ">>> generate_zipcodes:"
14
+ end
15
+
16
+ def add_gems
17
+ add_gem "mocha", :group => :test
18
+ end
19
+
20
+ def create_models
21
+ template 'zipcode_model.rb', "app/models/zipcode.rb"
22
+ template 'county_model.rb', "app/models/county.rb"
23
+ template 'state_model.rb', "app/models/state.rb"
24
+ end
25
+
26
+ # Implement the required interface for Rails::Generators::Migration.
27
+ # taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
28
+ def self.next_migration_number(dirname)
29
+ if ActiveRecord::Base.timestamped_migrations
30
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
31
+ else
32
+ "%.3d" % (current_migration_number(dirname) + 1)
33
+ end
34
+ end
35
+
36
+ def create_rakefile
37
+ template 'zipcodes.rake', "lib/tasks/zipcodes.rake"
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ require 'memoist'
2
+ class County < ActiveRecord::Base
3
+ extend Memoist
4
+
5
+ belongs_to :state
6
+ has_many :zipcodes
7
+
8
+ validates :name, uniqueness: {:scope => :state_id, :case_sensitive => false}, presence: true
9
+
10
+ scope :without_zipcodes, -> { joins("LEFT JOIN zipcodes ON zipcodes.county_id = counties.id").where("zipcodes.county_id IS NULL")}
11
+ scope :without_state, -> {where("state_id IS NULL")}
12
+
13
+ def cities
14
+ zipcodes.map(&:city).sort.uniq
15
+ end
16
+ memoize :cities
17
+ end
@@ -0,0 +1,17 @@
1
+ require 'memoist'
2
+ class County < ActiveRecord::Base
3
+ extend Memoist
4
+
5
+ belongs_to :state
6
+ has_many :zipcodes
7
+
8
+ validates :name, uniqueness: {:scope => :state_id, :case_sensitive => false}, :presence => true
9
+
10
+ scope :without_zipcodes, -> { joins("LEFT JOIN zipcodes ON zipcodes.county_id = counties.id").where("zipcodes.county_id IS NULL")}
11
+ scope :without_state, -> {where("state_id IS NULL")}
12
+
13
+ def cities
14
+ zipcodes.map(&:city).sort.uniq
15
+ end
16
+ memoize :cities
17
+ end
@@ -0,0 +1,41 @@
1
+ class CreateUsZipcodeModels < ActiveRecord::Migration
2
+ def self.up
3
+ # Zipcodes Table
4
+ create_table :zipcodes do |t|
5
+ t.string :code
6
+ t.string :city
7
+ t.integer :state_id, foreign_key: true
8
+ t.integer :county_id, foreign_key: true
9
+ t.decimal :lat, :precision => 15, :scale => 10
10
+ t.decimal :lon, :precision => 15, :scale => 10
11
+ t.timestamps
12
+ end
13
+ add_index :zipcodes, :code
14
+ add_index :zipcodes, :county_id
15
+ add_index :zipcodes, :state_id
16
+ add_index :zipcodes, [:lat, :lon]
17
+
18
+ # States Table
19
+ create_table :states do |t|
20
+ t.string :abbr, :limit => 2
21
+ t.string :name
22
+ t.timestamps
23
+ end
24
+ add_index :states, :abbr
25
+
26
+ # Counties Table
27
+ create_table :counties do |t|
28
+ t.integer :state_id
29
+ t.string :name
30
+ t.timestamps
31
+ end
32
+ add_index :counties, :name
33
+ add_index :counties, :state_id
34
+ end
35
+
36
+ def self.down
37
+ drop_table :counties
38
+ drop_table :states
39
+ drop_table :zipcodes
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ class CreateMyZipcodeGemModels < ActiveRecord::Migration
2
+ def self.up
3
+ # Zipcodes Table
4
+ create_table :zipcodes do |t|
5
+ t.string :code
6
+ t.string :city
7
+ t.integer :state_id, foreign_key: true
8
+ t.integer :county_id, foreign_key: true
9
+ t.decimal :lat, :precision => 15, :scale => 10
10
+ t.decimal :lon, :precision => 15, :scale => 10
11
+ t.timestamps
12
+ end
13
+ add_index :zipcodes, :code
14
+ add_index :zipcodes, :county_id
15
+ add_index :zipcodes, :state_id
16
+ add_index :zipcodes, [:lat, :lon]
17
+
18
+ # States Table
19
+ create_table :states do |t|
20
+ t.string :abbr, :limit => 2
21
+ t.string :name
22
+ t.timestamps
23
+ end
24
+ add_index :states, :abbr
25
+
26
+ # Counties Table
27
+ create_table :counties do |t|
28
+ t.integer :state_id
29
+ t.string :name
30
+ t.timestamps
31
+ end
32
+ add_index :counties, :name
33
+ add_index :counties, :state_id
34
+ end
35
+
36
+ def self.down
37
+ drop_table :counties
38
+ drop_table :states
39
+ drop_table :zipcodes
40
+ end
41
+ end
@@ -0,0 +1,15 @@
1
+ require 'memoist'
2
+ class State < ActiveRecord::Base
3
+ extend Memoist
4
+
5
+ has_many :zipcodes
6
+ has_many :counties
7
+
8
+ validates :abbr, uniqueness: { :case_sensitive => false }, presence: true
9
+ validates :name, uniqueness: { :case_sensitive => false }, presence: true
10
+
11
+ def cities
12
+ zipcodes.map(&:city).sort.uniq
13
+ end
14
+ memoize :cities
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'memoist'
2
+ class State < ActiveRecord::Base
3
+ extend Memoist
4
+
5
+ has_many :zipcodes
6
+ has_many :counties
7
+
8
+ validates :abbr, uniqueness: { :case_sensitive => false }, :presence => true
9
+ validates :name, uniqueness: { :case_sensitive => false }, :presence => true
10
+
11
+ def cities
12
+ zipcodes.map(&:city).sort.uniq
13
+ end
14
+ memoize :cities
15
+ end
@@ -0,0 +1,30 @@
1
+ class Zipcode < ActiveRecord::Base
2
+
3
+ belongs_to :county
4
+ belongs_to :state
5
+
6
+ validates :code, uniqueness: true, presence: true
7
+ validates :state_id, :county_id, :city, presence: true
8
+
9
+ scope :without_county, -> { where("county_id IS NULL") }
10
+ scope :without_state, -> { where("state_id IS NULL") }
11
+ scope :ungeocoded, -> { where("lat IS NULL OR lon IS NULL") }
12
+
13
+ class << self
14
+ def find_by_city(city)
15
+ includes(:county).where("city like '#{city}%'")
16
+ end
17
+ end
18
+
19
+ def county_and_zip
20
+ "#{county.name}: #{code}"
21
+ end
22
+
23
+ def latlon
24
+ [lat, lon]
25
+ end
26
+
27
+ def is_geocoded?
28
+ (!lat.nil? && !lon.nil?)
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ class Zipcode < ActiveRecord::Base
2
+
3
+ belongs_to :county
4
+ belongs_to :state
5
+
6
+ validates :code, uniqueness: true, presence: true
7
+ validates :state_id, :county_id, :city, :presence => true
8
+
9
+ scope :without_county, -> { where("county_id IS NULL") }
10
+ scope :without_state, -> { where("state_id IS NULL") }
11
+ scope :ungeocoded, -> { where("lat IS NULL OR lon IS NULL") }
12
+
13
+ class << self
14
+ def find_by_city(city)
15
+ includes(:county).where("city like '#{city}%'")
16
+ end
17
+ end
18
+
19
+ def county_and_zip
20
+ "#{county.name}: #{code}"
21
+ end
22
+
23
+ def latlon
24
+ [lat, lon]
25
+ end
26
+
27
+ def is_geocoded?
28
+ (!lat.nil? && !lon.nil?)
29
+ end
30
+ end
@@ -0,0 +1,163 @@
1
+ require 'open-uri'
2
+ require 'csv'
3
+ namespace :zipcodes do
4
+
5
+ desc "Update states table"
6
+ task :update_states => :environment do
7
+ puts ">>> Begin update of states table..."
8
+ url = "https://github.com/midwire/free_zipcode_data/raw/master/all_us_states.csv"
9
+ data = open(url)
10
+ file = nil
11
+ if data.is_a? StringIO
12
+ file = Tempfile.new('all_us_states.csv')
13
+ file.write(data.read)
14
+ file.flush
15
+ file.close
16
+ else
17
+ file = data
18
+ end
19
+ CSV.foreach(file.path, :headers => true) do |row|
20
+ puts "Updating state: [#{row['name']}]"
21
+ state = State.where(abbr: row['abbr']).first_or_initialize
22
+ state.update_attribute(:name, row['name'])
23
+ end
24
+ data.close
25
+ puts ">>> End update of states table..."
26
+ end
27
+
28
+ desc "Update counties table"
29
+ task :update_counties => :update_states do
30
+ puts ">>> Begin update of counties table..."
31
+ url = "https://github.com/midwire/free_zipcode_data/raw/master/all_us_counties.csv"
32
+ data = open(url)
33
+ file = nil
34
+ if data.is_a? StringIO
35
+ file = Tempfile.new('all_us_counties.csv')
36
+ file.write(data.read)
37
+ file.flush
38
+ file.close
39
+ else
40
+ file = data
41
+ end
42
+ CSV.foreach(file.path, :headers => true) do |row|
43
+ puts "Updating county: [#{row['name']}]"
44
+ # lookup state
45
+ state = State.find_by_abbr!(row['state'])
46
+ county = County.where(name: row['name'], state_id: state.to_param).first_or_initialize
47
+ county.save
48
+ end
49
+ data.close
50
+ puts ">>> End update of counties table..."
51
+ end
52
+
53
+ desc "Update zipcodes table"
54
+ task :update_zipcodes => :update_counties do
55
+ puts ">>> Begin update of zipcodes table..."
56
+ url = "https://github.com/midwire/free_zipcode_data/raw/master/all_us_zipcodes.csv"
57
+ data = open(url)
58
+ file = nil
59
+ if data.is_a? StringIO
60
+ file = Tempfile.new('all_us_zipcodes.csv')
61
+ file.write(data.read)
62
+ file.flush
63
+ file.close
64
+ else
65
+ file = data
66
+ end
67
+ CSV.foreach(file.path, :headers => true) do |row|
68
+ puts "Updating zipcode: [#{row['code']}], '#{row['city']}, #{row['state']}, #{row['county']}"
69
+ # lookup state
70
+ state = State.find_by_abbr!(row['state'])
71
+ begin
72
+ county = County.find_by_name_and_state_id!(row['county'], state.to_param)
73
+ rescue Exception => e
74
+ puts ">>> e: [#{e}]"
75
+ puts ">>>> No county found for zipcode: [#{row['code']}], '#{row['city']}, #{row['state']}, #{row['county']}... SKIPPING..."
76
+ next
77
+ end
78
+ zipcode = Zipcode.where(code: row['code']).first_or_initialize
79
+ zipcode.update_attributes!(
80
+ :city => row['city'].titleize,
81
+ :state_id => state.to_param,
82
+ :county_id => county.to_param,
83
+ :lat => row['lat'],
84
+ :lon => row['lon']
85
+ )
86
+ end
87
+ data.close
88
+ puts ">>> End update of zipcodes table..."
89
+ end
90
+
91
+ desc "Populate or update the zipcodes related tables"
92
+ task :update => :environment do
93
+ Rake::Task['zipcodes:update_zipcodes'].invoke
94
+ end
95
+
96
+ desc "Export US States to a .csv file"
97
+ task :export_states => :environment do
98
+ @states = State.order("name ASC")
99
+ csv_string = CSV.generate do |csv|
100
+ csv << ["abbr", "name"]
101
+ @states.each do |state|
102
+ csv << [
103
+ state.abbr,
104
+ state.name
105
+ ]
106
+ end
107
+ end
108
+ filename = "all_us_states.csv"
109
+ open("#{Rails.root}/db/#{filename}", 'w') do |f|
110
+ f.write(csv_string)
111
+ end
112
+ end
113
+
114
+ desc "Export all US Counties to a .csv file"
115
+ task :export_counties => :environment do
116
+ @counties = County.order("name ASC")
117
+ csv_string = CSV.generate do |csv|
118
+ csv << ["name", "state", "county_seat"]
119
+ @counties.each do |county|
120
+ csv << [
121
+ county.name,
122
+ county.state.abbr,
123
+ county.county_seat
124
+ ]
125
+ end
126
+ end
127
+ filename = "all_us_counties.csv"
128
+ open("#{Rails.root}/db/#{filename}", 'w') do |f|
129
+ f.write(csv_string)
130
+ end
131
+ end
132
+
133
+ desc "Export the zipcodes with county and state data"
134
+ task :export_zipcodes => :environment do
135
+ @zipcodes = Zipcode.order("code ASC")
136
+ csv_string = CSV.generate do |csv|
137
+ csv << ["code", "city", "state", "county", "area_code", "lat", "lon"]
138
+ @zipcodes.each do |zip|
139
+ csv << [
140
+ zip.code,
141
+ zip.city,
142
+ zip.state.abbr,
143
+ zip.county.nil? ? '' : zip.county.name,
144
+ zip.area_code,
145
+ zip.lat,
146
+ zip.lon
147
+ ]
148
+ end
149
+ end
150
+ filename = "all_us_zipcodes.csv"
151
+ open("#{Rails.root}/db/#{filename}", 'w') do |f|
152
+ f.write(csv_string)
153
+ end
154
+ end
155
+
156
+ desc "Export zipcodes, states and counties tables"
157
+ task :export => :environment do
158
+ Rake::Task['zipcodes:export_states'].invoke
159
+ Rake::Task['zipcodes:export_counties'].invoke
160
+ Rake::Task['zipcodes:export_zipcodes'].invoke
161
+ end
162
+
163
+ end