How to integrate Google Maps in a Rails app

The major part of my experiment was going to be the integration with Google Maps. At first, I was a bit apprehensive about it, but Ruby on Rails being a community oriented language, I found a couple of quite useful plug-ins. With them, finding a location based on address or geocode or finding nearby places based on certain radius of a location were not too hard.

There is actually an excellent book also, called Beginning Google maps applications with Rails and Ajax. But the problem with the book is that it was geared towards more for java developers using rails. Thus, its major functions were javascripts and it showed how to talk to rails app. In my case, since I wanted simple features and I didn’t want to take time to learn javascript, I decided to find a simpler way.

And I found that for things I wanted to do, I could do with YM4R/GM and Geokit. There are other excellent tutorials out there like the one by Jason Gilmore on Developer.com.

Let’s begin.

1. Sign-up for Google Maps API by going to here. For development environment, you can use either http://localhost:3000 or http://127.0.0.1:300 as the website URL. Copy the API key.

When you move to production environment, make sure you come back here to get another key for production URL.

2. Install YM4R/GM. From your rails app root directory,

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

2.1. Edit the config/gmap_api_key.yml and put your API key in the development section.

development:
  [Your development API KEY]
test:
  [Your development API KEY]
production:
  [Your production API KEY]

3. Install Geokit for Rails. From your rails app root directory,

script/plugin install git://github.com/andre/geokit-rails.git

Also add the following line inside Rails::Initializer.run do |config| in config/environment.rb.

Rails::Initializer.run do |config|
  [OTHER CODES]
  config.gem "geokit"
end

Last, install the gem.

rake gems:install

3.1. Add lat and lng fields to your database using migration. I am using my controller as an example, so substitute it with your controller.

ruby script/generate migration AddGeoToPlaygrounds

Then edit the migration file.

class AddGeoToPlaygrounds < ActiveRecord::Migration
  def self.up
    add_column :playgrounds, :lat, :float
    add_column :playgrounds, :lng, :float
  end
  def self.down
    remove_column :playgrounds, :lat
    remove_column :playgrounds, :lng
  end
end

3.2. Do rake db:migrate, and now you are ready to put Google Maps in your rails app.

4. Find a location

4.1. If you want to place a marker for a place, you have to pass longitude and latitude, not the full address. Then, how do you find the geocodes from an address? That's where Geokit comes in handy.

First put the following line early on in a controller where you will use the geocode.

include Geokit::Geocoders

Also add acts_as_mappable to the model where you want to use the geocode caluculation. In my case, it would be playground model.

class Playground < ActiveRecord::Base
  acts_as_mappable
end

There are many neat things you can do as you see in the example here.

In my case, the first is to find a location by user's IP address. You can use IpGeocoder method, but I found that it's not all that accurate.

@user_location = IpGeocoder.geocode(request.remote_ip)
if @user_location.success
   lat = @user_location.lat
   lng = @user_location.lng
end

If you have an address and want to find a geocode, then you can use MultiGeocoder.geocode. You can use any form of address: full address, city/state, or just zip. If you want to get a geocode for zip code 94085,

loc = MultiGeocoder.geocode('94085')

The geocode can be accessed by looking at loc.lat and loc.lng. The response to 94085 zip code looks like this.

Google geocoding. Address: 94085. Result: 

 94085

 200
 geocode

Sunnyvale, CA 94085, USA
USUSACASanta ClaraSunnyvale 94085 -122.0127067,37.3864411,0

If you have a geocode, you can also get an address by using GoogleGeocoder.reverse_geocode. When do the following,

addr = GoogleGeocoder.reverse_geocode [lat, lng]

you can access the address by looking at addr.street_address, addr.city, addr.state and addr.zip.

4.2. Once you have lat and lng, you can create a map. In a controller, initiate a map variable. Available options are explained in the rubyforge page. The following lines create a map, loads controls (like zoom level on the left side of a map), and centers the map at the lat, lng coordinate with a zoom level 13.

@map = GMap.new("map_div")
@map.control_init(:large_map => true, :map_type => true)
@map.center_zoom_init([lat,lng], 13)

4.3. After that, I find nearby playgrounds at the lat, lng coordinate in the same controller. This is a function of Geokit. It is finding all the playgrounds within 5 miles radius from lat, lng coordinate, ordered by average rating. Rating is function of acts_as_rated. Paginate will display only certain number of records per page specified by params[:page].

@playgrounds = Playground.find(:all, :origin => [lat, lng], :within => 5, :order => "rating_avg DESC").paginate :page => params[:page]

4.4. Once that's done, you have create markers and pass them to the @map variable. I didn't want put html codes in the controller (MVC violation!), but I couldn't really find a better way to do it. The content of infotxt will appear in the bubble when a user click on the marker.

@playgrounds.each do |p|
  infotxt = "#{p.name}
#{p.address}
#{p.city}, #{p.state} #{p.zip.to_s}" marker = GMarker.new([p.lat, p.lng], :title => p.name, :info_window => infotxt) @map.overlay_init(marker) end

4.5. Now, the map is finally ready to be displayed. First load GMap header information by adding the following line in the header field in app/views/layouts/application.html.erb.


 <%= GMap.header %>

4.6. Then in a view where you want to place a map,

<%= @map.to_html %>
<%= @map.div(:width => 600, :height => 400) %>

Then viola! You should see the map in your view.

Mine has all the logic in the rails. However, if you put your logic in the javascript, then you should be able to do many cool things you see on Google Maps like showing driving direction, finding things nearby, etc. from the bubble window.

Some day I will move them to javascript side, but so far this way serves my purpose.

In the next post, I will talk about how to get new location from user and center the map to a new location using ruby javascript, rjs.

Post to Twitter

14 thoughts on “How to integrate Google Maps in a Rails app

  1. That seems like a good candidate to stuff into a helper:

    def generate_info_text p
    #{p.name}
    #{p.address}
    #{p.city}, #{p.state} #{p.zip.to_s}”
    end

    then just have:

    infotxt = generate_info_text p

    in your controller.

  2. Hi,

    I need to trigger right click event on map and show pop up and also draw a circle based on radius. If you have any idea. Please help me.

  3. Pingback: mac

  4. Pingback: Kumarakom Kerala

  5. Pingback: Kumarakom

  6. Pingback: SPFMoisturizers

  7. Pingback: katadyn hiker pro

  8. Commonly I do not read post about sites, even so wish to state that this specific write-up pretty forced me to take a look at as well as practice it! Your creating flavor is amazed me personally. Appreciate it, pretty fantastic document.

Leave a Reply

Your email address will not be published. Required fields are marked *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax