Для одного из моих текущих проектов я выполнил нечто очень похожее на то, что вы пытаетесь сделать. Важно учитывать, что вы не хотите делать новый запрос геокодирования каждый раз, когда модель сохраняется. Это довольно трудоемкий и неэффективный процесс, если вам не нужно каждый раз получать новые геоординаты.
Кроме того, результаты геокодирования, полученные с 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