对于我目前的一个项目,我完成了与您正在尝试做的非常相似的事情。要考虑的一件大事是,您不希望每次保存模型时都执行新的地理编码请求。如果您不需要每次都获取新的地理坐标,则这样做相当耗时且效率低下。
此外,从 IP 地址获得的地理编码结果非常不准确。有时你会得到不错的结果,但很多时候你会得到附近另一个城镇的某个数据中心的坐标。如果您正在寻找区域精度,IP 地理编码精度可能足以满足您的要求。
如果属性没有改变,我就是这样解决不重新请求地理编码的问题:
require 'us_states' # this is just an array of states and abbreviations
include Geokit::Geocoders
class Location < ActiveRecord::Base
acts_as_mappable
validates_presence_of :name, :address_1, :city, :state, :zip
validates_format_of :zip, :with => /^([0-9]{5})(-[0-9]{4})?$/
validates_inclusion_of :state, :in => US_STATES_ABRS
before_save :get_geo_coords
# request_geocoding attribute is intended to help with unit testing
attr_accessor_with_default :request_geocoding, true
private
def get_geo_coords
# if lat and lng are already defined
if self.lat && self.lng && self.id
# find existing location
l = Location.find(self.id)
# and if location params are the same as existing location
# then we do not need to request geocords again
loc_attrs = %w{address_1 address_2 city state zip}
if loc_attrs.all? {|attr| self.attribute_for_inspect(attr) == l.attribute_for_inspect(attr)}
self.request_geocoding = false
end
end
if self.request_geocoding
# Request new geocoding
loc = MultiGeocoder.geocode("#{self.address_1}, #{self.city}, #{self.state}, #{self.zip}")
if loc.success
self.lat = loc.lat
self.lng = loc.lng
else
errors.add_to_base("Unable to geocode your location. Are you sure your address information is correct?")
end
end
end
end