module GeospatialObject METERS_PER_MILE = 1609.34 module Callbacks def set_geographic_point ActiveRecord::Base.connection.execute(<<-TEXT UPDATE addresses SET geographic_point = ST_GeographyFromText('POINT(' || longitude || ' ' || latitude || ')') WHERE id = #{self.id} TEXT ) end end def self.extended(base) base.send(:include, Callbacks) base.after_save :set_geographic_point base.set_rgeo_factory_for_column( :geographic_point, RGeo::Geographic.spherical_factory(srid: 4326) ) end def by_location(coordinates, distance_in_miles) distance_in_meters = distance_in_miles * METERS_PER_MILE if coordinates.blank? scoped else where( "ST_DWithin(geographic_point, st_setsrid(st_makepoint(?, ?), 4326), ?)", coordinates[:longitude], coordinates[:latitude], distance_in_meters ) end end def order_by_distance(coordinates) if coordinates.blank? scoped else order(distance_from_coordinates(coordinates)) end end def distance_from_coordinates(coordinates) search_point = RGeo::Geographic.spherical_factory.point( coordinates[:longitude], coordinates[:latitude] ) "ST_Distance(geographic_point, ST_GeographyFromText('#{search_point}'))/#{METERS_PER_MILE}" end module_function :distance_from_coordinates end