Permalink
Browse files

first run at multiple location fields

  • Loading branch information...
1 parent 3b0921c commit 48d4ab7fd4cf3481db77898334982771310bb6d6 @DaveSanders committed Jul 5, 2013
@@ -8,10 +8,11 @@ module ActiveRecord
##
# Set attribute names and include the Geocoder module.
#
- def geocoded_by(address_attr, options = {}, &block)
+ def geocoded_by(options = {}, &block)
geocoder_init(
:geocode => true,
- :user_address => address_attr,
+ :prefixes => options[:prefixes] || [''],
+ :address => options[:address] || :address,
:latitude => options[:latitude] || :latitude,
:longitude => options[:longitude] || :longitude,
:geocode_block => block,
@@ -30,11 +30,10 @@ def reverse_geocoded_by
def geocoder_init(options)
unless @geocoder_options
- @geocoder_options = {}
+ @geocoder_options = options
require "geocoder/stores/#{geocoder_file_name}"
include Geocoder::Store.const_get(geocoder_module_name)
end
- @geocoder_options.merge! options
end
end
end
@@ -1,3 +1,4 @@
+
# -*- coding: utf-8 -*-
require 'geocoder/sql'
require 'geocoder/stores/base'
@@ -14,58 +15,57 @@ module ActiveRecord
#
def self.included(base)
base.extend ClassMethods
- base.class_eval do
+ #Setup dynamic methods
+
+ #If prefixes is blank, then we get the usual methods
+ #otherwise we loop through the multiple prefixes to create all the methods for each scope
+
+ lat = base.geocoder_options[:latitude]
+ lng = base.geocoder_options[:longitude]
+
+ base.geocoder_options[:prefixes].each do |pre|
+ _pre = pre.empty? ? '' : "_#{pre}"
+ pre_ = pre.empty? ? '' : "#{pre}_"
- # scope: geocoded objects
- scope :geocoded, lambda {
- where("#{geocoder_options[:latitude]} IS NOT NULL " +
- "AND #{geocoder_options[:longitude]} IS NOT NULL")
+
+ base.class_eval %Q{
+ scope :#{pre_}geocoded, lambda {
+ where("#{pre_}#{lat} IS NOT NULL AND #{pre_}#{lng} IS NOT NULL")
+ }
}
- # scope: not-geocoded objects
- scope :not_geocoded, lambda {
- where("#{geocoder_options[:latitude]} IS NULL " +
- "OR #{geocoder_options[:longitude]} IS NULL")
+ base.class_eval %Q{
+ scope :#{pre_}not_geocoded, lambda {
+ where("#{pre_}#{lat} IS NULL AND #{pre_}#{lng} IS NULL")
+ }
}
- ##
- # Find all objects within a radius of the given location.
- # Location may be either a string to geocode or an array of
- # coordinates (<tt>[lat,lon]</tt>). Also takes an options hash
- # (see Geocoder::Orm::ActiveRecord::ClassMethods.near_scope_options
- # for details).
- #
- scope :near, lambda{ |location, *args|
- latitude, longitude = Geocoder::Calculations.extract_coordinates(location)
- if Geocoder::Calculations.coordinates_present?(latitude, longitude)
- options = near_scope_options(latitude, longitude, *args)
- select(options[:select]).where(options[:conditions]).
+ base.class_eval %Q{
+ scope :near#{_pre}, lambda {|location, *args|
+ latitude, longitude = Geocoder::Calculations.extract_coordinates(location)
+ if Geocoder::Calculations.coordinates_present?(latitude, longitude)
+ options = near_scope_options("#{pre}", latitude, longitude, *args)
+ select(options[:select]).where(options[:conditions]).
order(options[:order])
- else
- # If no lat/lon given we don't want any results, but we still
- # need distance and bearing columns so you can add, for example:
- # .order("distance")
- select(select_clause(nil, "NULL", "NULL")).where(false_condition)
- end
- }
+ else
+ select(select_clause(nil, "NULL", "NULL")).where(false_condition)
+ end
+ }
+ }
- ##
- # Find all objects within the area of a given bounding box.
- # Bounds must be an array of locations specifying the southwest
- # corner followed by the northeast corner of the box
- # (<tt>[[sw_lat, sw_lon], [ne_lat, ne_lon]]</tt>).
- #
- scope :within_bounding_box, lambda{ |bounds|
- sw_lat, sw_lng, ne_lat, ne_lng = bounds.flatten if bounds
- if sw_lat && sw_lng && ne_lat && ne_lng
- where(Geocoder::Sql.within_bounding_box(
- sw_lat, sw_lng, ne_lat, ne_lng,
- full_column_name(geocoder_options[:latitude]),
- full_column_name(geocoder_options[:longitude])
- ))
- else
- select(select_clause(nil, "NULL", "NULL")).where(false_condition)
- end
+ base.class_eval %Q{
+ scope :#{pre_}within_bounding_box, lambda{ |bounds|
+ sw_lat, sw_lng, ne_lat, ne_lng = bounds.flatten if bounds
+ if sw_lat && sw_lng && ne_lat && ne_lng
+ where(Geocoder::Sql.within_bounding_box(
+ sw_lat, sw_lng, ne_lat, ne_lng,
+ full_column_name(geocoder_options[:latitude]),
+ full_column_name(geocoder_options[:longitude])
+ ))
+ else
+ select(select_clause(nil, "NULL", "NULL")).where(false_condition)
+ end
+ }
}
end
end
@@ -108,23 +108,27 @@ def distance_from_sql(location, *args)
# * +:distance_column+ - used to set the column name of the calculated distance.
# * +:bearing_column+ - used to set the column name of the calculated bearing.
#
- def near_scope_options(latitude, longitude, radius = 20, options = {})
+ def near_scope_options(prefix, latitude, longitude, radius = 20, options = {})
+ prefix = prefix.empty? ? '' : "#{prefix}_"
if options[:units]
options[:units] = options[:units].to_sym
end
options[:units] ||= (geocoder_options[:units] || Geocoder.config.units)
select_distance = options.fetch(:select_distance, true)
options[:order] = "" if !select_distance && !options.include?(:order)
select_bearing = options.fetch(:select_bearing, true)
- bearing = bearing_sql(latitude, longitude, options)
- distance = distance_sql(latitude, longitude, options)
- distance_column = options.fetch(:distance_column, 'distance')
- bearing_column = options.fetch(:bearing_column, 'bearing')
+ bearing = bearing_sql(prefix, latitude, longitude, options)
+ distance = distance_sql(prefix, latitude, longitude, options)
+ distance_column = prefix + options.fetch(:distance_column, 'distance')
+ bearing_column = prefix + options.fetch(:bearing_column, 'bearing')
+ latitude_column = prefix + geocoder_options[:latitude].to_s
+ longitude_column = prefix + geocoder_options[:longitude].to_s
+
b = Geocoder::Calculations.bounding_box([latitude, longitude], radius, options)
args = b + [
- full_column_name(geocoder_options[:latitude]),
- full_column_name(geocoder_options[:longitude])
+ full_column_name(latitude_column),
+ full_column_name(longitude_column)
]
bounding_box_conditions = Geocoder::Sql.within_bounding_box(*args)
@@ -148,13 +152,13 @@ def near_scope_options(latitude, longitude, radius = 20, options = {})
# SQL for calculating distance based on the current database's
# capabilities (trig functions?).
#
- def distance_sql(latitude, longitude, options = {})
+ def distance_sql(prefix, latitude, longitude, options = {})
method_prefix = using_sqlite? ? "approx" : "full"
Geocoder::Sql.send(
method_prefix + "_distance",
latitude, longitude,
- full_column_name(geocoder_options[:latitude]),
- full_column_name(geocoder_options[:longitude]),
+ full_column_name(prefix + geocoder_options[:latitude].to_s),
+ full_column_name(prefix + geocoder_options[:longitude].to_s),
options
)
end
@@ -163,7 +167,7 @@ def distance_sql(latitude, longitude, options = {})
# SQL for calculating bearing based on the current database's
# capabilities (trig functions?).
#
- def bearing_sql(latitude, longitude, options = {})
+ def bearing_sql(prefix, latitude, longitude, options = {})
if !options.include?(:bearing)
options[:bearing] = Geocoder.config.distances
end
@@ -172,8 +176,8 @@ def bearing_sql(latitude, longitude, options = {})
Geocoder::Sql.send(
method_prefix + "_bearing",
latitude, longitude,
- full_column_name(geocoder_options[:latitude]),
- full_column_name(geocoder_options[:longitude]),
+ full_column_name(prefix + geocoder_options[:latitude].to_s),
+ full_column_name(prefix + geocoder_options[:longitude].to_s),
options
)
end
@@ -239,13 +243,21 @@ def full_column_name(column)
# (or other as specified in +geocoded_by+). Returns coordinates (array).
#
def geocode
- do_lookup(false) do |o,rs|
- if r = rs.first
- unless r.latitude.nil? or r.longitude.nil?
- o.__send__ "#{self.class.geocoder_options[:latitude]}=", r.latitude
- o.__send__ "#{self.class.geocoder_options[:longitude]}=", r.longitude
+ geocoder_options[:prefixes].each do |pre|
+ p = pre.empty? ? pre : "#{pre}_"
+ a = "#{p}#{self.class.geocoder_options[:address].to_s}"
+ address = self.send(a) if self.respond_to? a
+
+ next if a.nil? || a.empty?
+
+ do_lookup(false, address) do |o,rs|
+ if r = rs.first
+ unless r.latitude.nil? or r.longitude.nil?
+ o.__send__ "#{p}#{self.class.geocoder_options[:latitude].to_s}=", r.latitude
+ o.__send__ "#{p}#{self.class.geocoder_options[:longitude].to_s}=", r.longitude
+ end
+ r.coordinates
end
- r.coordinates
end
end
end
@@ -268,5 +280,6 @@ def reverse_geocode
end
alias_method :fetch_address, :reverse_geocode
+
end
-end
+end
@@ -91,12 +91,12 @@ def reverse_geocode
# given two-arguments: the object being geocoded and an array of
# Geocoder::Result objects).
#
- def do_lookup(reverse = false)
+ def do_lookup(reverse = false, address=nil)
options = self.class.geocoder_options
if reverse and options[:reverse_geocode]
query = to_coordinates
elsif !reverse and options[:geocode]
- query = send(options[:user_address])
+ query = send(address)
else
return
end

0 comments on commit 48d4ab7

Please sign in to comment.