Is this your first visit? You may want to subscribe to the feed.

Articles tagged with acts_as_geocodable

Location-based search with Sphinx and acts_as_geocodable

Sphinx, everybody’s favorite search engine, has support for location-based search, giving you geo-aware, full-text searching. So now you can find all of the garage sales on Saturday within 20 miles that have LPs and a reel mower.

All you need to do is add latitude and longitude (in radians) to the index, allowing you to limit the results to records within a distance of a point. The hardest part is getting the coordinates, but acts_as_geocodable makes that really easy.

To start, install acts_as_geocodable. Once you have that configured properly, install ThinkingSphinx, define an index on your geocodable model and add the coordinates to the index:

class Listing < ActiveRecord::Base
  acts_as_geocodable

  define_index do
    indexes title
    indexes description

    has geocoding.geocode(:id), :as => :geocode_id
    has 'RADIANS(geocodes.latitude)', :as => :latitude, :type => :float
    has 'RADIANS(geocodes.longitude)', :as => :longitude, :type => :float
  end
end

The three lines that start with has add the geocode id, and the latitude and longitude in radians to the index. Our index doesn’t need the geocode id, but we have to add it so that ThinkingSphinx properly joins the geocodes table.

After you rebuild the index and start the daemon, you can search for records by location. Here’s an example of taking a zip code from a user and finding all records with in 20 miles. (Note: you will need to grab the latest version, 0.2.9, of Graticule for this next bit of code to work)

def search
  location = Geocode.geocoder.locate(params[:zip]).coordinates.map(&:to_radians)
  @listings = Listing.search(params[:q], :geo => location,
    :with => {'@geodist' => 0.0..(20 * 1610.0)})
end

After looking up the coordinates of the zip code that the user entered, we do a search with the :geo parameter, limiting the results using the special @geodist condition. We have to pass in a range of floats that represent the distance of the points in meters (and since the US is in the stone age, I’m converting from miles).

That’s all there is to it. Now go write some cool location-based search and comment here about it.

Code: acts_as_geocodable Apr 14, 2009 ● updated Apr 14, 2009 3 comments

Graticule can failover

Graticule has a new geocoder that simply calls other geocoders in succession until it gets a result.

geocoder = Graticule.service(:multi).new(
  Graticule.service(:google).new("api_key"),
  Graticule.service(:yahoo).new("api_key"),
)
geocoder.locate '49423' # <= tries geocoders in succession

This can also be used in acts_as_geocodable by simply setting Geocode.geocoder to the new multi-geocoder. See the API docs for more information.

Thanks to Matt King for some ideas on the implementation and Ben Tucker for nudging me to implement it.

Code: acts_as_geocodable Sep 12, 2007 ● updated Sep 12, 2007 5 comments

Google adds more countries to geocoder

Google has added support for India, Hong Kong, Taiwan, Singapore, and Ireland to their geocoder. If you’re using Graticule, it should Just Work™. Let me know if you have any problems.

Code: acts_as_geocodable Aug 02, 2007 1 comment

Graticule and acts_as_geocodable go international

The single biggest request that I’ve gotten for Graticule and acts_as_geocodable has been for international support. So, for those outside the US (50% that read this blog according to google analytics), I have a present for you.

Last weekend I committed support for Local Search Maps (thanks to James Stewart), and PostcodeAnywhere, both of which have some international support, at least for Canada and Europe. I also added geocoder.ca.

Most of the international geocoding services seem to require a little more structured parameters, so with Graticule 0.2, all of the geocoders can take a hash (and some require it). As a result of gaining international support, the field names that Graticule uses have been changed to be more international-friendly: street, locality, region, postal_code, and country.

g = Graticule.service(:local_search_maps).new
location = g.locate :street => '48 Leicester Square', :locality => 'London', :country => 'UK'
location.coordinates  #=> [51.510036, -0.130427]

Geocoding IP Addresses

Several people mentioned that they would rather use acts_as_geocodable, but chose to use GeoKit, another good geocoding library (but with a little different philosophy), because it had support for geocoding IP addresses. So, with a flick of the wrist and a twitch of the nose, Graticule now supports HostIP for geocoding IP addresses:

g = Graitucle.service(:host_ip).new
location = g.locate "64.233.167.99"

location.coordinates  #=> [37.402, -122.078]
location.locality     #=> "Mountain View"
location.country      #=> "US"
location.region       #=> "CA"

Along with this, acts_as_geocodable has a helper method, remote_location:

@nearest_store = Store.find(:nearest, :origin => remote_location) if remote_location

Be careful not to rely too heavily on remote_location because the location of many IP addresses cannot be determined through HostIP.

Feedback

I’m just an ignorant North-American, so I would love some feedback from people using Graticule and acts_as_geocodable outside the US.

Code: acts_as_geocodable Mar 26, 2007 1 comment

Geocoding as easy as 1-2...

3?, nope there is no 3. Geocoding as easy as 1-2!

  1. Create your models
  2. Find them!
event = Event.create :street => "777 NE Martin Luther King, Jr. Blvd.",
  :city => "Portland", :region => "Oregon", :postal_code => 97232

# how far am I from RailsConf 2007?
event.distance_to "49423" #=> 1807.66560483205

# Find our new event, and any other ones in the area
Event.find(:all, :within => 50, :origin => "97232")

# Find the nearest restaurant with beer
Restaurant.find(:nearest, :origin => event, :conditions => 'beer = true')

I know you’re excited, so instead of blabbing on-and-on, FAQ-style:

How are you performing this voodoo?

A slick new plugin called acts_as_geocodable.

How do I get it?

script/plugin install -x git://github.com/collectiveidea/acts_as_geocodable.git

How do I set it up?

Its all in the README.

Why did you write this when there’s already several geocoding plugins?

The Ruby geocoding space is pretty fragmented right now. There’s all kinds of geocoders available, and none of them provide everything. We’re determined to fix that with Graticule and acts_as_geocodable.

We believe that all the heavy lifting of geocoding, distance calculations, etc., should be left to a gem, and only code that is directly related to Rails should be a Rails plugin. Even more, all the different geocoders should be available in the same package and have the same interface. A plugin should then be built on top of the gem that makes your apps geo-capabilities seem like voodoo.

We started our own projects because we didn’t think anyone else got it right. Recently, Bill Eisenhaur and Andre Lewis did a pretty good job, and we borrowed some of their ideas, but I still have issues with their approach and code, mainly that it’s all tied up into a Rails plugin.

Did you get it right?

I think we have a great foundation. It’s not perfect, nor does it have all the features of the other packages, but I think it is well architected.

Why don’t you work together?

Excellent idea! We would love to.

How does this fit in with JWZ’s use case?

(Why are you asking this?) A third of the problem is knowing where, a third is when, and a third is who. You’re on your own for the who and when.

Happy geocoding!

Code: acts_as_geocodable Feb 13, 2007 ● updated Jun 19, 2008 15 comments

Subscribe

Browse by Tag