Geokit and Authlogic, geocoding users' IPs when creating a user
Has anyone done this? I am confused as to how I can make this work, first I have a user model
Geocoding with it works great in IRB, just can't figure out how to get it to work in my project.
Trying to use some examples from the readme here: http://github.com/andre/geokit-rails/tree/master .
Anyway, here's what I have:
class User < ActiveRecord::Base
# geokit
acts_as_mappable
after_save :locate
def locate
location = Geokit::Geocoders::MultiGeocoder.geocode("12.12.12.12")
end
end
This matches my save action in mine userController
, I need to do this after saving as authlogic provides the IP after the user or session is saved. I think I'll end up making it a background process, but so far, how can I get this to work? I have a location column in a custom model that I will save the resultsgeocode()
Also right now I have some arbitrary IP address "12.12.12.12", but in fact it should be current_login_ip
For one of my current projects, I achieved something very similar to what you are trying to do. Note that you do not want to run a new geocoding request every time the model is saved. This is time consuming and inefficient if you don't need to get new geo coordinates every time.
Also, the geocoding results obtained from IP addresses are highly imprecise. Sometimes you will get decent results, but a lot of time you will get the coordinates of some data center in another nearby city. If you're looking for regional accuracy, IP geocoding accuracy might be good enough for what you're trying to do.
This is how I solved the problem of not reassigning geocoding if the attributes haven't changed:
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
Haven't used geokit myself, so I can't comment. But thought I should mention that browser-aware HTML 5 (like Firefox 3.5) support the geolocation API if you didn't know.
Check this site:
http://geokit.rubyforge.org/readme.html
Scroll down to the IP Geocoding and IP Geocoding section.
"You can get the location for an IP at any time using a geocoder like in the following example:"
location = IpGeocoder.geocode('12.215.42.19')
"where Location is a GeoLoc instance containing the latitude, longitude, city, state, and country code. Also, the success value is true.
Once you get your GeoLoc, just pull the user model, set its long / latin columns and save it.
GeoLoc doc: http://geokit.rubyforge.org/api/geokit-gem/Geokit/GeoLoc.html
Did I miss something?