Rails geopositioning with Google Maps

Posted: October 1st, 2009 | Author: Pierre Olivier Martel | Filed under: Rails | Comments

A common problem when building a Rails web application that deals with addresses is geopositioning. Geopositioning can have different meaning depending on what you’re trying to achieve. In this article and the following, I will describe my solution to the following problems :

  1. The user enters an address and you need to validate it and geoposition it (latitude & longitude) on a map.
  2. You need to display the google map for that given address on a webpage.

Today, I will show you how I did the first step using the YM4R/GM plugin.

1- Setup the plugin and get you Google Maps key

First thing to do is to install the YM4R/GM plugin plugin. There is also a gem but it seems to be a stripped-down version of the plugin. I couldn’t get it working so I would advise to use the plugin :

script/plugin install svn://rubyforge.org/var/svn/ym4r/Plugins/GM/trunk/ym4r_gm

The plugin creates a file in your config folder named gmaps_api_key.xml. You need to enter your Google Maps API keys for the different environments. You can get the keys here.

2- Create the model

Next thing to do is to create your Geolocation activerecord model. You need to at least have those four attributes :

create_table "geolocations", :force => true do |t|
  t.string   "address"
  t.string   "city"
  t.float    "latitude"
  t.float    "longitude"
end

You might also want to add the country and postal code to the mix. But in most case, Google Maps will be able to return you a location with just a street address and a city.

3- Set the geolocation on the before_save

When you create a new gelocation record, you want to geoposition it. Here’s my code in the Geolocation.rb model :

before_save :set_geolocation

def set_geolocation
  if changes['address'] || changes['city'] || !mapped?
    results = Geocoding::get(complete_address)
    if results.status == Geocoding::GEO_SUCCESS
      self.latitude, self.longitude = results[0].latlon
    else  
      self.latitude, self.longitude = nil
    end
  end
end

def complete_address
  [address, city].select(&:present?).join(', ')
end

def mapped?
  latitude && longitude
end

What this does is set the latitude and longitude for the given address on the before_save callback. We first check if the address or the city changed and if so we try to get a geocoding. If the API responds with SUCCESS, we set the latitude and longitude with the first result. If the API failed to return a valid address, we set the latitude and longitude to nil. We can check if the address was mapped using the mapped? method.

4- Wrap it up

Geopositionning the address is only the first part of the problem. Next week I’ll show you how to use the latitude and longitude information we stored to display Google maps in your webpages.

Next week : How to display a google map for a geopositioned address


  • neilmaffitt
    When I tried to install script/plugin install svn:// ... in the root of my project it did not create the gmaps_api_key file in my config. No errors were displayed it is like it did nothing. Any ideas?
  • Then just create manually a gmaps_api_key.yml and add :
    development:
    your-dev-key
    test:
    your-test-key
    production:
    your-production-key
  • Well, with the proper indentation as well! (which seems to get lost with this comment system)
  • Dave
    Hey this is a neat trick. I didn't think about having the model emit its own map. You just cleaned up my controllers quite a bit. Thanks! :D
  • Thanks Jacek, I didn't know about that trick. I will try it out!
  • There's a simple way to get the location without the need of api key: add this (http://www.google.com/jsapi ) script to you page and you now have something like this:

    google.loader.ClientLocation = {"latitude":50.317,"longitude":18.933,"address":{"city":"Chorzow","region":"Silesia","country":"Poland","country_code":"PL"}};
blog comments powered by Disqus