module Geocoder::Store::ActiveRecord

Public Class Methods

included(base) click to toggle source

Implementation of ‘included’ hook method.

# File lib/geo-calculator/store/active_record.rb, line 15
def self.included(base)
  base.extend ClassMethods
  base.class_eval do

    # scope: geocoded objects
    scope :geocoded, lambda {
      where("#{table_name}.#{geocoder_options[:latitude]} IS NOT NULL " +
        "AND #{table_name}.#{geocoder_options[:longitude]} IS NOT NULL")
    }

    # scope: not-geocoded objects
    scope :not_geocoded, lambda {
      where("#{table_name}.#{geocoder_options[:latitude]} IS NULL " +
        "OR #{table_name}.#{geocoder_options[:longitude]} 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::Store::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]).
          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_value, null_value)).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_value, null_value)).where(false_condition)
      end
    }
  end
end

Public Instance Methods

add_exclude_condition(conditions, exclude) click to toggle source

Adds a condition to exclude a given object by ID. Expects conditions as an array or string. Returns array.

# File lib/geo-calculator/store/active_record.rb, line 214
def add_exclude_condition(conditions, exclude)
  conditions = [conditions] if conditions.is_a?(String)
  if exclude
    conditions[0] << " AND #{full_column_name(primary_key)} != ?"
    conditions << exclude.id
  end
  conditions
end
bearing_sql(latitude, longitude, options = {}) click to toggle source

SQL for calculating bearing based on the current database’s capabilities (trig functions?).

# File lib/geo-calculator/store/active_record.rb, line 172
def bearing_sql(latitude, longitude, options = {})
  if !options.include?(:bearing)
    options[:bearing] = Geocoder.config.distances
  end
  if options[:bearing]
    method_prefix = using_sqlite? ? "approx" : "full"
    Geocoder::Sql.send(
      method_prefix + "_bearing",
      latitude, longitude,
      full_column_name(options[:latitude] || geocoder_options[:latitude]),
      full_column_name(options[:longitude]|| geocoder_options[:longitude]),
      options
    )
  end
end
distance_sql(latitude, longitude, options = {}) click to toggle source

SQL for calculating distance based on the current database’s capabilities (trig functions?).

# File lib/geo-calculator/store/active_record.rb, line 157
def distance_sql(latitude, longitude, options = {})
  method_prefix = using_sqlite? ? "approx" : "full"
  Geocoder::Sql.send(
    method_prefix + "_distance",
    latitude, longitude,
    full_column_name(options[:latitude] || geocoder_options[:latitude]),
    full_column_name(options[:longitude]|| geocoder_options[:longitude]),
    options
  )
end
false_condition() click to toggle source

Value which can be passed to where() to produce no results.

# File lib/geo-calculator/store/active_record.rb, line 241
def false_condition
  using_sqlite? ? 0 : "false"
end
full_column_name(column) click to toggle source

Prepend table name if column name doesn’t already contain one.

# File lib/geo-calculator/store/active_record.rb, line 248
def full_column_name(column)
  column = column.to_s
  column.include?(".") ? column : [table_name, column].join(".")
end
null_value() click to toggle source

Use OID type when running in PosgreSQL

# File lib/geo-calculator/store/active_record.rb, line 234
def null_value
  using_postgres? ? 'NULL::text' : 'NULL'
end
select_clause(columns, distance = nil, bearing = nil, distance_column = 'distance', bearing_column = 'bearing') click to toggle source

Generate the SELECT clause.

# File lib/geo-calculator/store/active_record.rb, line 191
def select_clause(columns, distance = nil, bearing = nil, distance_column = 'distance', bearing_column = 'bearing')
  if columns == :id_only
    return full_column_name(primary_key)
  elsif columns == :geo_only
    clause = ""
  else
    clause = (columns || full_column_name("*"))
  end
  if distance
    clause += ", " unless clause.empty?
    clause += "#{distance} AS #{distance_column}"
  end
  if bearing
    clause += ", " unless clause.empty?
    clause += "#{bearing} AS #{bearing_column}"
  end
  clause
end
using_postgres?() click to toggle source
# File lib/geo-calculator/store/active_record.rb, line 227
def using_postgres?
  connection.adapter_name.match(/postgres/i)
end
using_sqlite?() click to toggle source
# File lib/geo-calculator/store/active_record.rb, line 223
def using_sqlite?
  connection.adapter_name.match(/sqlite/i)
end