Geocoding as easy as 1-2...
3?, nope there is no 3. Geocoding as easy as 1-2!
- Create your models
- 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!








14 comments
Great work. This is what I wanted to do but was short on time when I wrote acts_as_geocode. You guys did a much more thorough job. I was just doing something quick to make my life easier on some real estate projects.
Now I will switch soon.
February 13, 2007 at 10:37 AM
Hi,
Thanks for the plugin! :)
I’ve installed Graticule and acts_as_geocodable but I can’t seem to get it to run reliably.
I’m on Windows XP, using a Yahoo Application id.
It seems setting Geocode.geocoder in the environment.rb isn’t “sticking”. It set when the app is loaded but is nil when Geocode.rb is hit as part of the save process.
I’m working around this by using:
end
Thanks!
Shawn
February 13, 2007 at 07:47 PM
Shawn,
That’s really odd. Looking through the code, I have no clue what would be causing that.
I don’t have immediate access to a Windows environment, so could you (or anyone else) help me debug it?
February 14, 2007 at 11:17 AM
Hi Brandon,
Sure – I’m kinda, sorta new to ROR but will try some things to see if cattr’s disappear on some other classes.
Here’s another item relating to Yahoo geocode requests…
In acts_as_geocoable.rb, the full_address method has a ”\n” after the street. This was causing Yahoo to return ZIP level precision vs STREET level. Google didn’t seem to mind.
Orignal:
def full_address returning(””) { |address| address << ”#{geo_attribute(:street)}\n” unless geo_attribute(:street).blank? address << ”#{geo_attribute(:city)}, ” unless geo_attribute(:city).blank? address << ”#{geo_attribute(:region)} ” unless geo_attribute(:region).blank? address << ”#{geo_attribute(:postal_code)}” unless geo_attribute(:postal_code).blank? address << ” #{geo_attribute(:country)}” unless geo_attribute(:country).blank? }.strip end
Changed to:
Basically I replaced the ”\n” with a ”,”. Yahoo now returns a STREET level precision on valid address. Google seems okay to.
Hope this helps!
Shawn
February 15, 2007 at 10:39 AM
Hi Brandon,
Tested out the geocoder.nil? issue on Win XP. It seems to only occur when the server is started in development mode. Production mode, the object seems to stay created.
I tested using Mongrel and WEBrick with same results.
Hope this helps!
Shawn
February 15, 2007 at 11:02 AM
Any thoughts of adding :through support for acts_as_geocodable? For example, say I have events which belong_to locations, it would be good to be able to search for forthcoming events based on their location.
I like the way acts_as_locateable implements that, but this plugin overall looks more appropriate for my needs.
February 17, 2007 at 11:18 AM
Your approach of separating concerns is great.
It seems to me that being able to order results by distance as well as selecting by :within is important. Do you have plans to do this? Suggestions on how I might do it?
Thanks again
March 07, 2007 at 09:09 PM
Peter,
Sorry for the late response, I fell off the face of the earth for a week. You should be able to order the results by passing
:order => 'distance'to the find. Let me know if that doesn’t work.March 14, 2007 at 11:08 PM
Something weird is going on… I can’t start the mongrel after installing the acts_as_geocodable plugin, it says that Graticules 0.2.0 is required and I have the 0.2.6 installed.. what am I doing wrong??
March 17, 2008 at 11:02 PM
I’ve installed the latest acts_as_geocodable and the latest Graticule, run the migrations, added the line into environment.rb (in development mode) and It Doesn’t Work™.
To start checking it works with my models I’ve uncommented the task in acts_as_geocodeable_tasks.rake, purely as a simple way to load my environment and test a model can become geocodeable. But when the environment loads I get “Unititialized constant Geocode”. Now I’m a new Rails user so there’s obviously some Rails idiom which is assumed in the instruction “just add this to your environment.rb”, but I don’t know what it is. Please clue me in, there must be something more I need to add to the environment.rb to get it to work.
May 21, 2008 at 12:53 PM
John,
Did you restart the server? Any time you install a plugin, you need to restart script/server.
May 28, 2008 at 03:50 PM
I’m running into the same problem that John Small is. Whenever I try to restart the server I get “Unititialized constant Geocode”
I’ve also tried adding “require ‘graticule’” to the environment.rb file as well with no luck.
Any help will be greatly appreciated. Thanks.
June 26, 2008 at 12:10 PM
I have the same problem reported about geocoder.nil:
NoMethodError: You have a nil object when you didn’t expect it! The error occurred while evaluating nil.latitude from (irb):6
However, this is on OSX with the latest Rails, Gratitude and ActsAsGeocoder.
However, I don’t think the issue is that Geocode.geocoder is not sticking because when on the same console session I type
Geocode.geocoder
I does return:
=> #<graticule::geocoder::google:0x22998dc><uri::http:0x114cb10 url:http: />, @key=”my-key”
So, it seems the problem is not related to the “stickiness” in environment.rb (neither development nor production). The problem seems to be somewhere in the AR methods added to the model not being able to access Geocode.geocoder.
Any clues anyone?
July 22, 2008 at 11:42 AM
I think I may know where the problem is.
I was looking at acts_as_geocodable.rb and found:
Which has the attributes hard coded in the array. Therefore, if your Model doesn’t have these exact attributes, then attach_geocode will fail and return nil. As a test, I just created instance methods in my model to return the values of my attributes based on the names in the array and now it works just fine.
It seems to be that this was somewhat documented in the README file and I must have missed it.
The problem I have is that my models looks something like this:
class Address < ActiveRecord::Base belongs_to :postal_code end
class PostalCode < ActiveRecord::Base belongs_to :state end
class State < ActiveRecord::Base belongs_to :country end
So, if I want to get the zip, city, and state of an address, I need:
address.postal_code.zip_code address.postal_code.state.iso2 address.postal_code.state.country.iso2
respectively.
If I were to use the recommendations in the README, how can I do this:
class Address < ActiveRecord::Base belongs_to :postal_code acts_as_geocodable :address => {:street => :street1, :locality => :postal_code.city, :region => :postal_code.state.iso2, :postal_code => :postal_code.zip_code } end
That doesn’t work for me unless instead I just define corresponding instance methods.
Any ideas?
Thanks
July 22, 2008 at 01:17 PM
Speak your mind: