peripatetic 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.DS_Store ADDED
Binary file
data/README.md CHANGED
@@ -1,8 +1,17 @@
1
- # Peripatetic
1
+ Peripatetic
2
+ This gem adds location functionality to any app it create 3 tables in the database (locations, countries, and postal_codes) and populates countries and postal_codes from a compressed yaml file. One may specify wether it be has_one or has_many. The countries and postal_codes table are just look up tables. in the form partial the gem guesses the country and zip code from the ip and fills it in. If it takes too long or the data is not there it doesn't populate it. The country table has a position field which you can use to order the countries. If a user adds a street address then it geocodes it and adds the updated lat lng to the locations table.
2
3
 
3
- TODO: Write a gem description
4
+ the postal codes are from geonames and the f
4
5
 
5
- ## Installation
6
+ countries db is from https://github.com/hexorx/countries
7
+ the postal_codes db is from http://download.geonames.org/export/dump/ and http://federalgovernmentzipcodes.us/
8
+
9
+ The US postal_codes lat and lng columns have been recently updated.
10
+
11
+
12
+ Drop in Location for any model has_one or has_many, creates a nested association and allows you to drop into your form a partial
13
+
14
+ Installation:
6
15
 
7
16
  Add this line to your application's Gemfile:
8
17
 
@@ -16,9 +25,29 @@ Or install it yourself as:
16
25
 
17
26
  $ gem install peripatetic
18
27
 
19
- ## Usage
28
+ Usage:
29
+
30
+ Add include Peripatetic to the model you want locations
31
+ then just drop in nested form into the form
32
+
33
+ <%= f.fields_for peripatetic_locations(model, number_of_times_to_build) do |builder| %><br>
34
+ <% if builder.object.new_record? %><br>
35
+ <%= builder.hidden_field :ip, :value => ip_address %><br>
36
+ <div class="field">
37
+ <%= builder.label :street %><br />
38
+ <%= builder.text_field :street %>
39
+ </div>
40
+ <div class="field">
41
+ <%= builder.label :accessor_postal_code, "Postal Code" %><br />
42
+ <%= builder.text_field :accessor_postal_code, :value => get_accessor_postal_code(builder.object)[:postal_code] %>
43
+ </div>
44
+ <div class="field">
45
+ <%= builder.label :accessor_country, "Country" %><br />
46
+ <%= builder.country_select :accessor_country, get_accessor_postal_code(builder.object)[:country] %>
47
+ </div>
48
+ <% end %><br>
49
+ <% end %><br>
20
50
 
21
- TODO: Write usage instructions here
22
51
 
23
52
  ## Contributing
24
53
 
@@ -0,0 +1,31 @@
1
+ class CreateCountries < ActiveRecord::Migration
2
+ def change
3
+ create_table :countries do |t|
4
+ t.string :name
5
+ t.string :continent
6
+ t.string :alpha2
7
+ t.string :alpha3
8
+ t.string :country_code
9
+ t.string :currency
10
+ t.string :international_prefix
11
+ t.string :ioc
12
+ t.float :latitude
13
+ t.float :longitude
14
+ t.string :names
15
+ t.string :national_destination_code_lengths
16
+ t.string :national_number_lengths
17
+ t.string :national_prefix
18
+ t.string :number
19
+ t.string :region
20
+ t.string :subregion
21
+ t.string :un_locode
22
+ t.string :languages
23
+ t.string :nationality
24
+ t.string :address_format
25
+ t.string :alt_currency
26
+ t.integer :position
27
+ t.timestamps
28
+ end
29
+ add_index :countries, :name, :position
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ class CreateLocations < ActiveRecord::Migration
2
+ def change
3
+ create_table :locations do |t|
4
+ t.string :street
5
+ t.string :city
6
+ t.string :region
7
+ t.string :region_code
8
+ t.string :postal_code
9
+ t.string :country
10
+ t.string :country_code
11
+ t.float :latitude
12
+ t.float :longitude
13
+ t.string :locationable_type
14
+ t.integer :locationable_id
15
+ t.boolean :geocoded
16
+ t.integer :country_id
17
+ t.timestamps
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ class CreatePostalCode < ActiveRecord::Migration
2
+ def change
3
+ create_table :postal_codes do |t|
4
+ t.string :name
5
+ t.string :city
6
+ t.string :region
7
+ t.string :region_code
8
+ t.string :country_code
9
+ t.float :latitude
10
+ t.float :longitude
11
+ t.boolean :geocoded
12
+ t.string :time_zone
13
+ t.integer :country_id
14
+ t.timestamps
15
+ end
16
+ add_index :postal_codes, :country_code
17
+ add_index :postal_codes, :name
18
+ end
19
+ end
@@ -0,0 +1,60 @@
1
+ ##### JSON
2
+ desc 'Dump a database to yaml fixtures. '
3
+ task :dump_fixtures => :environment do
4
+ path = ENV['FIXTURE_DIR'] || "#{Rails.root}/data"
5
+
6
+ ActiveRecord::Base.establish_connection(Rails.env.to_sym)
7
+ ActiveRecord::Base.connection.tables.each do |table_name|
8
+ if table_name == "postal_codes"
9
+ i = 0
10
+ File.open("#{path}/#{table_name}.json", 'wb') do |file|
11
+ file.write ActiveRecord::Base.connection.
12
+ select_all("SELECT * FROM #{table_name}").inject({}) { |hash, record|
13
+ hash["#{table_name}_#{i += 1}"] = record
14
+ hash
15
+ }.to_json
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ desc "Reset Database data to that in fixtures that were dumped"
22
+ task :load_dumped_fixtures => :environment do
23
+ require 'active_record/fixtures'
24
+ ActiveRecord::Base.establish_connection(Rails.env.to_sym)
25
+ path = ENV['FIXTURE_DIR'] || "#{Rails.root}/data"
26
+ Dir.glob("#{path}/*.{json}").each do |fixture_file|
27
+ ActiveRecord::Fixtures.create_fixtures(path, File.basename(fixture_file, '.*'))
28
+ end
29
+ end
30
+
31
+ ##### YAML
32
+ task :dump_fixtures_yaml => :environment do
33
+ path = ENV['FIXTURE_DIR'] || "#{Rails.root}/data"
34
+
35
+ ActiveRecord::Base.establish_connection(Rails.env.to_sym)
36
+ ActiveRecord::Base.connection.tables.each do |table_name|
37
+ if table_name == "postal_codes" or table_name == "countries"
38
+ i = 0
39
+ File.open("#{path}/#{table_name}.yml", 'wb') do |file|
40
+ file.write ActiveRecord::Base.connection.
41
+ select_all("SELECT * FROM #{table_name}").inject({}) { |hash, record|
42
+ hash["#{table_name}_#{i += 1}"] = record
43
+ hash
44
+ }.to_yaml
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ desc "Reset Database data to that in fixtures that were dumped"
51
+ task :load_dumped_fixtures_yaml => :environment do
52
+ require 'active_record/fixtures'
53
+
54
+
55
+ ActiveRecord::Base.establish_connection(Rails.env.to_sym)
56
+ path = ENV['FIXTURE_DIR'] || "#{Rails.root}/data"
57
+ Dir.glob("#{path}/*.{yml}").each do |fixture_file|
58
+ ActiveRecord::Fixtures.create_fixtures(path, File.basename(fixture_file, '.*'))
59
+ end
60
+ end
data/lib/peripatetic.rb CHANGED
@@ -1,6 +1,113 @@
1
1
  require "peripatetic/version"
2
2
  require 'peripatetic/location'
3
+ require 'peripatetic/postal_code'
4
+ require 'peripatetic/country'
3
5
 
4
6
  module Peripatetic
5
- # Your code goes here...
7
+ def self.included(base)
8
+ # base.extend(ClassMethods).relate
9
+ base.extend ClassMethods
10
+
11
+ base.class_eval do
12
+ attr_accessible :locations_attributes #, :location_attributes
13
+ has_many :locations, :as => :locationable, :class_name => "Peripatetic::Location"
14
+ accepts_nested_attributes_for :locations, :reject_if => lambda { |a| a[:accessor_postal_code].blank? }, :allow_destroy => true
15
+ # has_one :location, :as => :locationable, :class_name => "Peripatetic::Location"
16
+ # accepts_nested_attributes_for :location, :reject_if => lambda { |a| a[:accessor_postal_code].blank? }, :allow_destroy => true
17
+ end
18
+
19
+ end
20
+
21
+ module ClassMethods
22
+ # def acts_as_peripatetic
23
+ # send :include, Peripatetic
24
+ # end
25
+ end
26
+
27
+ module ModelMethods
28
+
29
+ end
30
+
31
+ module HelperMethods
32
+ def nested_form_builder
33
+ # <%= f.fields_for poly_locations(@user, 1) do |builder| %>
34
+ # <% if builder.object.new_record? %>
35
+ # <%= builder.hidden_field :ip, :value => ip_address %>
36
+ # <div class="field">
37
+ # <%= builder.label :street %><br />
38
+ # <%= builder.text_field :street %>
39
+ # </div>
40
+ # <div class="field">
41
+ # <%= builder.label :accessor_postal_code, "Postal Code" %><br />
42
+ # <%= builder.text_field :accessor_postal_code, :value => get_accessor_postal_code(builder.object)[:postal_code] %>
43
+ # </div>
44
+ # <div class="field">
45
+ # <%= builder.label :accessor_country, "Country" %><br />
46
+ # <%= builder.country_select :accessor_country, get_accessor_postal_code(builder.object)[:country] %>
47
+ # </div>
48
+ # <% end %>
49
+ # <% end %>
50
+ end
51
+
52
+ def all_countries
53
+ Country.select([:id, :name, :position]).order("position ASC")
54
+ end
55
+
56
+ def ip_address
57
+ (Rails.env.development? or Rails.env.test?) ? '206.127.79.163' : (env['HTTP_X_REAL_IP'] ||= env['REMOTE_ADDR'])
58
+ end
59
+
60
+ def get_country
61
+ if builder.object.accessor_postal_code.present?
62
+ @get_country = { :ip => ip_address, :country => builder.object.accessor_country, :postal_code => builder.object.accessor_postal_code }
63
+ else
64
+ res = Geocoder.search(ip_address)
65
+ if res.first
66
+ @get_country = { :ip => ip_address, :country => res.first.country, :postal_code => res.first.postal_code }
67
+ end
68
+ end
69
+ end
70
+
71
+ def get_accessors(model)
72
+ @get_accessors ||= get_accessor_postal_code(model)
73
+ end
74
+
75
+ def get_accessor_postal_code(model)
76
+ # return unless @get_accessor_postal_code.blank?
77
+ if model.postal_code.blank?
78
+ res = Geocoder.search(ip_address)
79
+ if res.first
80
+ country = Country.select([:id, :name, :position]).find_by_name(res.first.country)
81
+ if country.present?
82
+ country_id = country.id
83
+ else
84
+ country_id = Country.select([:id, :name, :position]).find_by_name("United States").id
85
+ end
86
+ model.country_id = country_id
87
+ @get_accessor_postal_code = { :ip => ip_address, :postal_code => res.first.postal_code }
88
+ else
89
+ @get_accessor_postal_code = { :ip => ip_address, :postal_code => "" }
90
+ end
91
+ else
92
+ @get_accessor_postal_code = { :ip => ip_address, :postal_code => model.postal_code }
93
+ end
94
+ end
95
+
96
+ def peripatetic_locations(model, amount=false)
97
+ if amount == false
98
+ # user.build_profile # this will work
99
+ model.build_location
100
+ :location
101
+ else
102
+ amount.times { model.locations.build } if model.new_record?
103
+ :locations
104
+ end
105
+ end
106
+ end
107
+
6
108
  end
109
+
110
+ ActionView::Base.send :include, Peripatetic::HelperMethods
111
+ # class ActiveRecord::Base
112
+ # include Peripatetic
113
+ # end
Binary file
@@ -0,0 +1,8 @@
1
+ module Peripatetic
2
+
3
+ class Country < ActiveRecord::Base
4
+ attr_accessible :name
5
+ has_many :postal_codes
6
+ end
7
+
8
+ end
@@ -0,0 +1,121 @@
1
+ require 'geocoder'
2
+ module Peripatetic
3
+
4
+ class Location < ActiveRecord::Base
5
+ attr_accessible :latitude, :longitude, :street, :accessor_country, :accessor_postal_code, :time_zone, :ip, :country_id
6
+ attr_accessor :accessor_country, :accessor_postal_code, :ip
7
+
8
+ belongs_to :locationable, :polymorphic => true
9
+ belongs_to :country
10
+ # belongs_to :postal_code
11
+
12
+ Geocoder.configure(:timeout => 1)
13
+ reverse_geocoded_by :latitude, :longitude
14
+ geocoded_by :location_attributes_available do |obj, results|
15
+ puts "Geocoding Yo!"
16
+ if geo = results.first
17
+ obj.latitude = geo.latitude if geo.latitude
18
+ obj.longitude = geo.longitude if geo.longitude
19
+ if geo.state.present? and geo.state_code.present?
20
+ obj.region = geo.state
21
+ end
22
+ obj.city = geo.city.downcase if geo.city.present?
23
+ obj.geocoded = true
24
+ end
25
+ end
26
+ # after_validation :geocode, :if => :street_or_postal_code_changed?
27
+
28
+ after_validation :geocode, :if => :street_present_or_changed?
29
+ after_validation :inject_location_info
30
+
31
+
32
+ validate :validate_postal_code
33
+ def validate_postal_code
34
+ return unless postal_code_changed? and postal_code.present?
35
+ if PostalCode.find_by_postal_code_and_country_code(accessor_postal_code, country.alpha2).present?
36
+ true
37
+ else
38
+ errors.add(:postal_code, "appears to be invalid")
39
+ false
40
+ end
41
+ end
42
+
43
+ def street?
44
+ street.present?
45
+ end
46
+
47
+ def city?
48
+ city.present?
49
+ end
50
+
51
+ def postal_code?
52
+ postal.present?
53
+ end
54
+
55
+ def accessor_postal_code?
56
+ accessor_postal_code.present?
57
+ end
58
+
59
+ def region?
60
+ region.present?
61
+ end
62
+
63
+ def accessor_country?
64
+ accessor_country.present?
65
+ end
66
+
67
+ def inject_location_info
68
+ # p_c = Peripatetic::PostalCode.find_by_postal_code_and_country_code("59601", (Peripatetic::Country.find(231).alpha2))
69
+ # p_c = Peripatetic::PostalCode.find_by_postal_code_and_country_code("59601", "US")
70
+ p_c = PostalCode.find_by_postal_code_and_country_code(accessor_postal_code, (country.alpha2))
71
+ puts "almost injecting"
72
+ return unless postal_code_changed? or self.new_record?
73
+ puts "injecting"
74
+ self.postal_code = p_c.postal_code
75
+ self.city = p_c.city
76
+ self.region = p_c.region
77
+ self.country_code = p_c.country_code
78
+ self.time_zone = p_c.time_zone unless p_c.time_zone == "f"
79
+ self.latitude = p_c.latitude
80
+ self.longitude = p_c.longitude
81
+ end
82
+
83
+ def street_present_or_changed?
84
+ return true if street_changed? and street.present?
85
+ end
86
+
87
+ def fill_in_city_region_postal_code
88
+ end
89
+
90
+ def location_attributes_available
91
+ if street? and accessor_postal_code?
92
+ "#{street} #{accessor_postal_code} #{accessor_country}"
93
+ elsif accessor_postal_code?
94
+ "#{accessor_postal_code} #{accessor_country}"
95
+ elsif accessor_country?
96
+ accessor_country
97
+ else
98
+ ip
99
+ end
100
+ end
101
+
102
+ def get_time_zone
103
+ # latitude = l.latitude
104
+ # longitude = l.longitude
105
+ url = "http://api.geonames.org/timezone?lat=#{latitude}&lng=#{longitude}&username=davinjay"
106
+ doc = Nokogiri::HTML(open(url))
107
+ doc.search("timezoneid").first.children.first.to_s
108
+ # self.postal_code.time_zone = self.time_zone
109
+ # self.postal_code.save
110
+ end
111
+
112
+ def city_address
113
+ "#{city} #{region}"
114
+ end
115
+
116
+ def full_address
117
+ ("#{street} #{city} #{region} #{postal}").chomp
118
+ end
119
+
120
+ end
121
+ end
@@ -0,0 +1,85 @@
1
+ # require "peripatetic/version"
2
+ # require 'peripatetic/location'
3
+ # require 'peripatetic/city'
4
+ # require 'peripatetic/country'
5
+ # require 'peripatetic/postal_code'
6
+ # require 'peripatetic/region'
7
+ #
8
+ # module Peripatetic
9
+ #
10
+ # module ClassMethods
11
+ # def peripateticize
12
+ # end
13
+ # # def acts_as_peripatetic
14
+ # # send :include, Peripatetic
15
+ # # end
16
+ # end
17
+ #
18
+ # module ModelMethods
19
+ #
20
+ # end
21
+ #
22
+ # module HelperMethods
23
+ # def nested_form_builder
24
+ # # <%= f.fields_for poly_locations(@user, 1) do |builder| %>
25
+ # # <% if builder.object.new_record? %>
26
+ # # <%= builder.hidden_field :ip, :value => ip_address %>
27
+ # # <div class="field">
28
+ # # <%= builder.label :street %><br />
29
+ # # <%= builder.text_field :street %>
30
+ # # </div>
31
+ # # <div class="field">
32
+ # # <%= builder.label :accessor_postal_code %><br />
33
+ # # <%= builder.text_field :accessor_postal_code, :value => get_accessor_postal_code(builder.object)[:postal_code] %>
34
+ # # </div>
35
+ # # <div class="field">
36
+ # # <%= builder.label :accessor_country %><br />
37
+ # # <%= builder.country_select :accessor_country, get_accessor_postal_code(builder.object)[:country] %>
38
+ # # </div>
39
+ # # <% end %>
40
+ # # <% end %>
41
+ # end
42
+ #
43
+ # def ip_address
44
+ # (Rails.env.development? or Rails.env.test?) ? '206.127.79.163' : (env['HTTP_X_REAL_IP'] ||= env['REMOTE_ADDR'])
45
+ # end
46
+ #
47
+ # def get_country
48
+ # # Geokit::Geocoders::google = "AIzaSyAi43R79isU8MeS7ISBxAdUUe2phnoxpoM"
49
+ # # res = GeoKit::Geocoders::IpGeocoder.geocode(ip_address)
50
+ # # if res.success
51
+ # # res.country
52
+ # # res.country_code
53
+ # # # get_country = {:country => res.country, :country_code => res.country_code}
54
+ # # end
55
+ # res = Geocoder.search(ip_address)
56
+ # if res.first
57
+ # @get_country = { :ip => ip_address, :country => res.first.country, :postal_code => res.first.postal_code }
58
+ # end
59
+ # end
60
+ #
61
+ # def get_accessor_postal_code(model)
62
+ # if model.postal_code.blank?
63
+ # res = Geocoder.search(ip_address)
64
+ # if res.first
65
+ # @get_accessor_postal_code = { :ip => ip_address, :country => res.first.country, :postal_code => res.first.postal_code }
66
+ # end
67
+ # else
68
+ # @get_accessor_postal_code = { :ip => ip_address, :country => model.postal_code.country_name, :postal_code => model.postal_code.name }
69
+ # end
70
+ # end
71
+ #
72
+ # def poly_locations(model, amount=false)
73
+ # if amount == false
74
+ # model.build_location
75
+ # else
76
+ # amount.times { model.locations.build }
77
+ # end
78
+ # :locations
79
+ # end
80
+ # end
81
+ # end
82
+ # ActionView::Base.send :include, Peripatetic::HelperMethods
83
+ #
84
+ # module Peripatetic::ActiveRecord
85
+ # end