diff --git a/lib/geocoder/model.rb b/lib/geocoder/model.rb index d8dcbfeeb7f2f909657616ca22b444cbd75fdccc..752ee8213c3bd7d2abd30f4ed9ab99359064b15f 100644 --- a/lib/geocoder/model.rb +++ b/lib/geocoder/model.rb @@ -8,32 +8,6 @@ module Geocoder module Model module Base - ## - # Set attribute names and include the Geocoder module. - # - def geocoded_by(address_attr, options = {}, &block) - geocoder_init( - :geocode => true, - :user_address => address_attr, - :latitude => options[:latitude] || :latitude, - :longitude => options[:longitude] || :longitude, - :geocode_block => block - ) - end - - ## - # Set attribute names and include the Geocoder module. - # - def reverse_geocoded_by(latitude_attr, longitude_attr, options = {}, &block) - geocoder_init( - :reverse_geocode => true, - :fetched_address => options[:address] || :address, - :latitude => latitude_attr, - :longitude => longitude_attr, - :reverse_block => block - ) - end - def geocoder_options @geocoder_options end @@ -60,6 +34,33 @@ module Geocoder module ActiveRecord include Base + + ## + # Set attribute names and include the Geocoder module. + # + def geocoded_by(address_attr, options = {}, &block) + geocoder_init( + :geocode => true, + :user_address => address_attr, + :latitude => options[:latitude] || :latitude, + :longitude => options[:longitude] || :longitude, + :geocode_block => block + ) + end + + ## + # Set attribute names and include the Geocoder module. + # + def reverse_geocoded_by(latitude_attr, longitude_attr, options = {}, &block) + geocoder_init( + :reverse_geocode => true, + :fetched_address => options[:address] || :address, + :latitude => latitude_attr, + :longitude => longitude_attr, + :reverse_block => block + ) + end + private def geocoder_file_name; "active_record"; end def geocoder_module_name; "ActiveRecord"; end @@ -67,9 +68,43 @@ module Geocoder module Mongoid include Base + + ## + # Set attribute names and include the Geocoder module. + # + def geocoded_by(address_attr, options = {}, &block) + geocoder_init( + :geocode => true, + :user_address => address_attr, + :coordinates => options[:coordinates] || :coordinates, + :geocode_block => block + ) + end + + ## + # Set attribute names and include the Geocoder module. + # + def reverse_geocoded_by(coordinates_attr, options = {}, &block) + geocoder_init( + :reverse_geocode => true, + :fetched_address => options[:address] || :address, + :coordinates => coordinates_attr, + :reverse_block => block + ) + end + + def self.included(base); base.extend(self); end private def geocoder_file_name; "mongoid"; end def geocoder_module_name; "Mongoid"; end + + def geocoder_init(options) + super(options) + + # create 2d index + index [[ geocoder_options[:coordinates], Mongo::GEO2D ]], + :min => -180, :max => 180 + end end end end diff --git a/lib/geocoder/orms/base.rb b/lib/geocoder/orms/base.rb index 666cfbc9ed3fab217cb54d73d110e5d309ec8ebd..0c018a497f73f093d3c6c8203999710ed0394f94 100644 --- a/lib/geocoder/orms/base.rb +++ b/lib/geocoder/orms/base.rb @@ -72,13 +72,12 @@ module Geocoder def do_lookup(reverse = false) options = self.class.geocoder_options if reverse and options[:reverse_geocode] - args = [:latitude, :longitude] + args = to_coordinates elsif !reverse and options[:geocode] - args = [:user_address] + args = [send(options[:user_address])] else return end - args.map!{ |a| send(options[a]) } if (results = Geocoder.search(*args)).size > 0 diff --git a/lib/geocoder/orms/mongoid.rb b/lib/geocoder/orms/mongoid.rb new file mode 100644 index 0000000000000000000000000000000000000000..462089635f2a9fa101d6b70c5f5ad573aa868277 --- /dev/null +++ b/lib/geocoder/orms/mongoid.rb @@ -0,0 +1,74 @@ +require 'geocoder/orms/base' + +module Geocoder::Orm + module Mongoid + include Base + + def self.included(base) + base.class_eval do + + scope :geocoded, lambda { + where(geocoder_options[:coordinates].ne => nil) + } + + scope :not_geocoded, lambda { + where(geocoder_options[:coordinates] => nil) + } + + scope :near, lambda{ |location, *args| + radius = args.size > 0 ? args.shift : 20 + options = args.size > 0 ? args.shift : {} + coords = location.is_a?(Array) ? + location : Geocoder.coordinates(location) + conds = {:coordinates => { + "$nearSphere" => coords.reverse, + "$maxDistance" => Geocoder::Calculations.distance_to_radians( + radius, options[:units] || :mi) + }} + if obj = options[:exclude] + conds[:_id.ne] = obj.id + end + criteria.where(conds) + } + end + end + + ## + # Coordinates [lat,lon] of the object. + # This method always returns coordinates in lat,lon order, + # even though internally they are stored in the opposite order. + # + def to_coordinates + coords = send(self.class.geocoder_options[:coordinates]) + coords.is_a?(Array) ? coords.reverse : nil + end + + ## + # Look up coordinates and assign to +latitude+ and +longitude+ attributes + # (or other as specified in +geocoded_by+). Returns coordinates (array). + # + def geocode + do_lookup(false) do |o,rs| + r = rs.first + unless r.coordinates.nil? + o.send :write_attribute, self.class.geocoder_options[:coordinates], r.coordinates.reverse + end + r.coordinates + end + end + + ## + # Look up address and assign to +address+ attribute (or other as specified + # in +reverse_geocoded_by+). Returns address (string). + # + def reverse_geocode + do_lookup(true) do |o,rs| + r = rs.first + unless r.address.nil? + o.send :write_attribute, self.class.geocoder_options[:fetched_address], r.address + end + r.address + end + end + end +end