Skip to content
Browse files

added auto_geocode to acts_as_mappable

git-svn-id: http://geokit.rubyforge.org/svn/trunk@35 9265c765-0211-4c68-b2df-6d1bd6e20c4d
  • Loading branch information...
1 parent 4f53732 commit 47e3d0c8a1d7de1f6f95ae5d6a648c91312e3e62 lewisac committed Jun 19, 2007
Showing with 66 additions and 2 deletions.
  1. +38 −1 lib/geo_kit/acts_as_mappable.rb
  2. +22 −1 test/acts_as_mappable_test.rb
  3. 0 test/fixtures/stores.yml
  4. +6 −0 test/schema.rb
View
39 lib/geo_kit/acts_as_mappable.rb
@@ -8,7 +8,7 @@ module GeoKit
# 2. a geocodeable string -- :origin=>'100 Spear st, San Francisco, CA'
# 3. an object which responds to lat and lng methods, or latitude and longitude methods,
# or whatever methods you have specified for lng_column_name and lat_column_name
- #
+ #
# Other finder methods are provided for specific queries. These are:
#
# * find_within (alias: find_inside)
@@ -34,6 +34,18 @@ module ClassMethods # :nodoc:
# GeoKit::default_formula. Also, by default, uses lat, lng, and distance for respective
# column names. All of these can be overridden using the :default_units, :default_formula,
# :lat_column_name, :lng_column_name, and :distance_column_name hash keys.
+ #
+ # Can also use to auto-geocode a specific column on create. Syntax;
+ #
+ # acts_as_mappable :auto_geocode=>true
+ #
+ # By default, it tries to geocode the "address" field. Or, for more customized behavior:
+ #
+ # acts_as_mappable :auto_geocode=>{:field=>:address,:error_message=>'bad address'}
+ #
+ # In both cases, it creates a before_validation_on_create callback to geocode the given column.
+ # For anything more customized, we recommend you forgo the auto_geocode option
+ # and create your own AR callback to handle geocoding.
def acts_as_mappable(options = {})
# Mix in the module, but ensure to do so just once.
return if self.included_modules.include?(GeoKit::ActsAsMappable::InstanceMethods)
@@ -48,9 +60,34 @@ def acts_as_mappable(options = {})
self.default_formula = options[:default_formula] || GeoKit::default_formula
self.lat_column_name = options[:lat_column_name] || 'lat'
self.lng_column_name = options[:lng_column_name] || 'lng'
+ if options.include?(:auto_geocode) && options[:auto_geocode]
+ # if the form auto_geocode=>true is used, let the defaults take over by suppling an empty hash
+ options[:auto_geocode] = {} if options[:auto_geocode] == true
+ cattr_accessor :auto_geocode_field, :auto_geocode_error_message
+ self.auto_geocode_field = options[:auto_geocode][:field] || 'address'
+ self.auto_geocode_error_message = options[:auto_geocode][:error_message] || 'could not locate address'
+
+ # set the actual callback here
+ before_validation_on_create :auto_geocode_address
+ end
end
end
+ # this is the callback for auto_geocoding
+ def auto_geocode_address
+ address=self.send(auto_geocode_field)
+ geo=GeoKit::Geocoders::MultiGeocoder.geocode(address)
+
+ if geo.success
+ self.send("#{lat_column_name}=", geo.lat)
+ self.send("#{lng_column_name}=", geo.lng)
+ else
+ errors.add(auto_geocode_field, auto_geocode_error_message)
+ end
+
+ geo.success
+ end
+
# Instance methods to mix into ActiveRecord.
module InstanceMethods #:nodoc:
# Mix class methods into module.
View
23 test/acts_as_mappable_test.rb
@@ -15,6 +15,11 @@ class Location < ActiveRecord::Base #:nodoc: all
acts_as_mappable
end
+# for auto_geocode
+class Store < ActiveRecord::Base
+ acts_as_mappable :auto_geocode=>true
+end
+
# Uses deviations from conventions.
class CustomLocation < ActiveRecord::Base #:nodoc: all
belongs_to :company
@@ -38,7 +43,7 @@ class ActsAsMappableTest < Test::Unit::TestCase #:nodoc: all
#puts "Rails Path #{RAILS_ROOT}"
#puts "Fixture Path: #{self.fixture_path}"
#self.fixture_path = ' /Users/bill_eisenhauer/Projects/geokit_test/test/fixtures/'
- fixtures :companies, :locations, :custom_locations
+ fixtures :companies, :locations, :custom_locations, :stores
def setup
@location_a = GeoKit::GeoLoc.new
@@ -457,4 +462,20 @@ def test_find_within_bounds_with_array_conditions
assert_equal 1, locations.size
end
+ def test_auto_geocode
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(@location_a)
+ store=Store.new(:address=>'Irving, TX')
+ store.save
+ assert_equal store.lat,@location_a.lat
+ assert_equal store.lng,@location_a.lng
+ assert_equal 0, store.errors.size
+ end
+
+ def test_auto_geocode_failure
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("BOGUS").returns(GeoKit::GeoLoc.new)
+ store=Store.new(:address=>'BOGUS')
+ store.save
+ assert store.new_record?
+ assert_equal 1, store.errors.size
+ end
end
View
0 test/fixtures/stores.yml
No changes.
View
6 test/schema.rb
@@ -22,4 +22,10 @@
t.column :latitude, :decimal, :precision => 15, :scale => 10
t.column :longitude, :decimal, :precision => 15, :scale => 10
end
+
+ create_table :stores, :force=> true do |t|
+ t.column :address, :string
+ t.column :lat, :decimal, :precision => 15, :scale => 10
+ t.column :lng, :decimal, :precision => 15, :scale => 10
+ end
end

0 comments on commit 47e3d0c

Please sign in to comment.
Something went wrong with that request. Please try again.