GeoKit: a plugin for location-based Rails apps

Feb 9, 2007 by Andre

I am happy to release GeoKit over at RubyForge. GeoKit has been a collaboration between myself and Bill Eisenhauer

What is GeoKit?

Geokit is a Rails plugin for building location-based apps. It provides geocoding, location finders, and distance calculation in one cohesive package. If you have any tables with latitude/longitude oolumns in your database, or if you every wanted to easily query for "all the stores within a 50 mile radius," then GeoKit is for you.

What can GeoKit do for you?

  • Distance calculations between two points on the earth. Calculate the distance in miles or KM, with all the trigonometry abstracted away by GeoKit.
  • ActiveRecord distance-based finders. For example, you can find all the points in your database within a 50-mile radius.
  • Geocoding from multiple providers. It currently supports Google, Yahoo, Geocoder.us, and Geocoder.ca geocoders, and it provides a uniform response structure from all of them. It also provides a fail-over mechanism, in case your input fails to geocode in one service.
  • IP-based location lookup utilizing hostip.info. Provide an IP address, and get city name and latitude/longitude in return.
  • A before_filter helper to geocode the user's location based on IP address, and retain the location in a cookie.

Examples?

Find near latitude and longitude:

Store.find(:all, :origin =>  [37.792, -122.393] :conditions=>'distance<10')

Find near an address:

Store.find(:all, :origin=>'100 Spear st, San Francisco, CA', :conditions=>'distance<10')

Geocode an address:

res=GeoKit::Geocoders::GoogleGeocoder.geocode('100 Spear st, San Francisco, CA') 
puts res.lat 

Find distance:

distance=first_location.distance_from(second_location, :units=>:miles)

Where can you get it?

Head over to GeoKit at RubyForge for the plugin source and API docs.

Or, skip right to installing it as a plugin:

ruby script/plugin install svn://rubyforge.org/var/svn/geokit/trunk

Comments

1

Greg on Feb 09

Awesome Andre, I'm definitely going to give it a try over the next few days. Your blog has helped me out tons with building location based rails apps, can't wait for the book!

Cheers,
Greg

2

Jeff Dean on Feb 09

Rock on!

I'd like to add a "county" or "region" field. Google returns a SubAdministrativeArea and it's a shame to discard it. If you were to add something like this, what would you call it (county, region etc...)?

I'll write a patch and some tests and submit it to rubyforge if you're open to it.

3

Brandon Keepers on Feb 09

Andre,

I posted on Bill's blog, but I thought I would also mention it here. I've also been working on something similar in the form of a gem and a plugin.

I'd love to figure out how we can work together.

Brandon

4

Lucian on Feb 10

You can use http://www.ipgp.net to get informations and map of IP address.

5

Doug on Feb 10

Does it support UK addresses and locations for address strings? Or is it only US?

6

Jordan Brock on Feb 10

Doug,

I've started using it with Australian addresses and it works fine. I've found that I need to send a string with either the full state name, or with "Australia" on the end.

eg

"10 Bland St, Ashfield, New South Wales, Australia"

7

Sanjay on Feb 13

I've implemented something similar, which I'm happy to replace with Geokit. During that implementation, I discovered that Google Maps runs from a different database than the geocoder. Sometimes maps has info that geocoder doesn't and vice versa.

I'd be happy to supply a patch that has this as (yet another) source. In the meantime, here's the code:

# google's geocoding dataset appears to be different than their mapping one.
# which means we can map stuff that we can't find!
# so, at the very end, make this request and snitch this string out of it
# http://maps.google.com/maps?q=123+Tonisgah+Road,+Phoenicia,+NY,+12464&ie=UTF8&om=1
def self.get_lat_long_google_maps(address)
match = /@([0-9.-]+),([0-9.-]+)/
h = Net::HTTP.new('maps.google.com', 80)
response = h.get("/maps?q=#{CGI.escape(address)}&ie=UTF8&om=1", nil)
lng = lat = nil

# modify search shows up if it is guessing
if response.message == "OK" && !(response.body[/Modify search/]) && ll = response.body[match]
lat = ll[/([0-9.-]+)/].to_f
lng = ll[ll.index(",")+1, 100].to_f # sloppy, but 'to the end'
return {:success=> true, :latitude=> lat, :longitude=> lng} if lat && lng
end
return {:success=> false, :latitude=> nil, :longitude=> nil}
end

Cheers,
sanj

8

Andre Lewis on Feb 13

Doug: right now the GeoLoc#full_address method will have some trouble with some non-US addresses. That's the method which takes the geocoding result, and formulates a full, displayable address. It's US-centric right now, although I would be happy to see patches (and tests :-) that correctly format results from multiple countries. Note through that parsing addresses from all over the world is complex; read up on xAL (http://www.oasis-open.org/committees/ciq/ciq.html#6) for more.

Sanjay: thanks for the code. Watch out for Google's terms of service when you're scraping the HTML though. By the way, I've also encountered discrepancies between Google's maps at maps.google.com, and the maps provided through the API. Whenever there's a discrepancy, the maps.google.com version seems to be more updated/accurate.

9

Tony on Feb 19

How does this come into play with spatial_adapter? It almost seems like a lot of these geographic projects should all be rolled into one.

10

Andre Lewis on Feb 20

Tony, I haven't tried GeoKit together with spatial_adapter, but I have mad respect for Guilhem Vellut's work. Reports from the field on using the two side-by-side are welcome.

There are lots of projects for which simple latitude/longitude columns are all you need to get the desired mapping functionality. I think GeoKit works well for these applications -- especially if you're just getting started -- as you don't have to worry about unfamiliar column types.

11

Aswin Anand on Apr 14

The plugin install url "svn://rubyforge.org/var/svn/geokit/trunk" doesn't work. On executing the command given at the http://geokit.rubyforge.org/, no folder gets created under vendor/plugins. Therefore, I downloaded the zip file, unzipped it and installed the geokit folder at vendor/plugins. Please modify the url at http://geokit.rubyforge.org/ to an existing one. Thanks!

12

Andre on Apr 16

Aswin, I just tried it and it worked. Perhaps you hit rubyforge at a moment they were down. BTW, the code download is at least a few revs behind -- definitely go back and get the trunk from Rubyforge.

13

Mohit on Jul 28

The plugin install url"svn://rubyforge.org/var/svn/geokit/trunk" doesn't work. On executing the command given at the http://geokit.rubyforge.org/, no folder gets created under vendor/plugins. Please modify the url at http://geokit.rubyforge.org/ to an existing one. Thanks!

14

ezekial on May 20

I have a question, once I install the plugin, how do I actually begin using it? There's no generator for a model for it, so do I just create a model with lat/long and the include the plugin? How does it effect the model?

15

David B on Aug 18

I love your plugin, and I bought your text on google maps apps w/ rails+ajax-AWESOME!

My web application which had been working fine has recently started giving me the Geocode errors stating there is a problem with 'normalize' in mappable.rb.

Any suggestions?

PS, I tried to delete it from my app, and upload a new plugin, but SVN seems to have a problem with this:
vendor/plugins/geokit/.svn' containing working copy admin area is missing

Any suggestions on how to gracefully update the plugin in an application under SVN control??

Thanks David

16

Kalyan Sir on Oct 07

The plugin install is not working. I followed the install instructions and used "svn://rubyforge.org/var/svn/geokit/trunk". Is there a different way to install the plugin?

Post a comment

 
This is so filters can reject the spam-bots. Thanks!