Skip to content
Snippets Groups Projects
Commit f937f3a7 authored by Alex Reisner's avatar Alex Reisner
Browse files

Add reverse geocoding to models.

parent 2adee1db
No related branches found
No related tags found
No related merge requests found
......@@ -101,6 +101,18 @@ If your model has +address+, +city+, +state+, and +country+ attributes you might
Please see the code for more methods and detailed information about arguments (eg, working with kilometers).
== Reverse Geocoding
If you need reverse geocoding (lat/long coordinates to address), do something like the following in your model:
reverse_geocoded_by :latitude, :longitude
after_validation :fetch_address
and make sure it has +latitude+ and +longitude+ attributes, as well as an +address+ attribute. As with regular geocoding, you can specify alternate names for all of these attributes, for example:
reverse_geocoded_by :lat, :lon, :address => :location
== SQLite
SQLite's lack of trigonometric functions requires an alternate implementation of the +near+ method (scope). When using SQLite, Geocoder will automatically use a less accurate algorithm for finding objects near a given point. Results of this algorithm should not be trusted too much as it will return objects that are outside the given radius.
......@@ -136,7 +148,6 @@ If anyone has a more elegant solution to this problem I am very interested in se
* use completely separate "drivers" for different AR adapters?
* seems reasonable since we're using very DB-specific features
* also need to make sure 'mysql2' is supported
* add reverse geocoding
* make 'near' scope work with AR associations
* http://stackoverflow.com/questions/3266358/geocoder-rails-plugin-near-search-problem-with-activerecord
* prepend table names to column names in SQL distance expression (required
......
......@@ -11,12 +11,36 @@ ActiveRecord::Base.class_eval do
# Set attribute names and include the Geocoder module.
#
def self.geocoded_by(address_attr, options = {})
class_inheritable_reader :geocoder_options
write_inheritable_attribute :geocoder_options, {
:address_attr => address_attr,
:latitude => options[:latitude] || :latitude,
:longitude => options[:longitude] || :longitude
}
include Geocoder::ActiveRecord
_geocoder_init({
:address => address_attr,
:latitude => options[:latitude] || :latitude,
:longitude => options[:longitude] || :longitude
})
end
##
# Set attribute names and include the Geocoder module.
#
def self.reverse_geocoded_by(latitude_attr, longitude_attr, options = {})
_geocoder_init({
:address => options[:address] || :address,
:latitude => latitude_attr,
:longitude => longitude_attr
})
end
def self._geocoder_init(options)
unless _geocoder_initialized?
class_inheritable_reader :geocoder_options
class_inheritable_hash_writer :geocoder_options
end
self.geocoder_options = options
unless _geocoder_initialized?
include Geocoder::ActiveRecord
end
end
def self._geocoder_initialized?
included_modules.include? Geocoder::ActiveRecord
end
end
......@@ -184,7 +184,7 @@ module Geocoder
#
def fetch_coordinates(save = false)
coords = Geocoder::Lookup.coordinates(
send(self.class.geocoder_options[:address_attr])
send(self.class.geocoder_options[:address])
)
unless coords.blank?
method = (save ? "update" : "write") + "_attribute"
......@@ -200,5 +200,28 @@ module Geocoder
def fetch_coordinates!
fetch_coordinates(true)
end
##
# Fetch address and assign +address+ attribute. Also returns
# address as a string.
#
def fetch_address(save = false)
address = Geocoder::Lookup.address(
send(self.class.geocoder_options[:latitude]),
send(self.class.geocoder_options[:longitude])
)
unless address.blank?
method = (save ? "update" : "write") + "_attribute"
send method, self.class.geocoder_options[:address], address
end
address
end
##
# Fetch address and update (save) +address+ data.
#
def fetch_address!
fetch_address(true)
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment