Module: ActsAsGeocodable

Defined in:
lib/acts_as_geocodable/remote_location.rb,
lib/acts_as_geocodable/version.rb,
lib/acts_as_geocodable.rb

Overview

:nodoc:

Defined Under Namespace

Modules: Model, RemoteLocation

Constant Summary collapse

VERSION =
'2.0.1'

Instance Method Summary collapse

Instance Method Details

#acts_as_geocodable(options = {}) ⇒ Object

Make a model geocodable.

class Event < ActiveRecord::Base
  acts_as_geocodable
end

Options

  • :address: A hash that maps geocodable attirbutes (:street, :locality, :region, :postal_code, :country) to your model’s address fields, or a symbol to store the entire address in one field

  • :normalize_address: If set to true, you address fields will be updated using the address fields returned by the geocoder. (Default is false)

  • :units: Default units-:miles or :kilometers-used for distance calculations and queries. (Default is :miles)



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/acts_as_geocodable.rb', line 30

def acts_as_geocodable(options = {})
  options = {
    :address => {
      :street => :street, :locality => :locality, :region => :region,
      :postal_code => :postal_code, :country => :country},
    :normalize_address => false,
    :distance_column => 'distance',
    :units => :miles
  }.merge(options)

  write_inheritable_attribute :acts_as_geocodable_options, options
  class_inheritable_reader :acts_as_geocodable_options

  define_callbacks :geocoding

  has_one :geocoding, :as => :geocodable, :include => :geocode, :dependent => :destroy

  after_save :attach_geocode

  # Would love to do a simpler scope here, like:
  # scope :with_geocode_fields, includes(:geocoding)
  # But we need to use select() and it would get overwritten.
  scope :with_geocode_fields, lambda {
    joins("JOIN geocodings ON
        #{table_name}.#{primary_key} = geocodings.geocodable_id AND
          geocodings.geocodable_type = '#{model_name}'
        JOIN geocodes ON geocodings.geocode_id = geocodes.id")
  }

  # Use ActiveRecord ARel style syntax for finding records.
  #
  #   Model.origin("Chicago, IL", :within => 10)
  #
  # a +distance+ attribute indicating the distance
  # to the origin is added to each of the results:
  #
  #   Model.origin("Portland, OR").first.distance #=> 388.383
  #
  # == Options
  #
  # * <tt>origin</tt>: A Geocode, String, or geocodable model that specifies
  #   the origin
  # * <tt>:within</tt>: Limit to results within this radius of the origin
  # * <tt>:beyond</tt>: Limit to results outside of this radius from the origin
  # * <tt>:units</tt>: Units to use for <tt>:within</tt> or <tt>:beyond</tt>.
  #   Default is <tt>:miles</tt> unless specified otherwise in the +acts_as_geocodable+
  #   declaration.
  #
  scope :origin, lambda {|*args|
    origin = location_to_geocode(args[0])
    options = {
      :units => acts_as_geocodable_options[:units],
    }.merge(args[1] || {})
    distance_sql = sql_for_distance(origin, options[:units])

    scope = with_geocode_fields.select("#{table_name}.*, #{distance_sql} AS
         #{acts_as_geocodable_options[:distance_column]}")

    scope = scope.where("#{distance_sql} >  #{options[:beyond]}") if options[:beyond]
    if options[:within]
      scope = scope.where("(#{distance_sql} <= #{options[:within]}) OR (geocodes.latitude = :lat AND geocodes.longitude = :long)", {:lat => origin.latitude, :long => origin.longitude})
    end
    scope
  }

  scope :near, order("#{acts_as_geocodable_options[:distance_column]} ASC")
  scope :far, order("#{acts_as_geocodable_options[:distance_column]} DESC")

  include ActsAsGeocodable::Model
end