RoR and Google Maps Mashup

Now that we have written a simple database backed application, let’s add a map to our Rails application.

Get a Google Maps Key

To start off, get a Google Maps API key:

http://www.google.com/apis/maps

Use the url: http://rordemo.com:3000

(Or you can use the key below.)

Google Maps Rails Files

To get started, follow these instructions to add some Google map code to your application.

application_helper.rb

First, in your app/helpers/application_helper.rb, add this method:

def map(options = {})
  gmap_defaults = {:width => "525", :height => "500",
    :center => "-122.18172311782837, 37.453261881659074",
    :zoom => "2",
    :key => MY_CONFIG[:google_key]
  } 
  @gmap = gmap_defaults.merge(options)
  @gmap[:marker] = @gmap[:center] if @gmap[:marker].nil?

  # Convert from single marker syntax to multiple markers syntax
  marker_hash = {}
  marker_hash[:point] = @gmap[:marker] if @gmap[:marker]
  marker_hash[:text] = @gmap[:text] if @gmap[:text]
  marker_hash[:url] = @gmap[:url] if @gmap[:url]
  markers = {:markers => [marker_hash]}
  @gmap = markers.merge(@gmap)

  render(:partial => "layouts/google_map", :no_layout => true)
end

_google_map.rhtml

Then create app/views/layouts/_google_map.rhtml:

<% @body_tag = 'onload="initMap()"' %>

<div id="map" style="width: <%= @gmap[:width] %>px; height: <%= @gmap[:height] %>px"></div>
<% if @gmap[:locator] %>
  <hr>
  <div id="message"></div>
<% end %> 

<script src="http://maps.google.com/maps?file=api&v=1&key=<%= @gmap[:key] %>" type="text/javascript"></script>

<script type="text/javascript">
//<![CDATA[

function initMap() {

  // Create a base icon for all of our markers that specifies the
    // shadow, icon dimensions, etc.
    var baseIcon = new GIcon();
    baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
    baseIcon.iconSize = new GSize(20, 34);
    baseIcon.shadowSize = new GSize(37, 34);
    baseIcon.iconAnchor = new GPoint(9, 34);
    baseIcon.infoWindowAnchor = new GPoint(9, 2);
    baseIcon.infoShadowAnchor = new GPoint(18, 25);

  // Center the map
  var map = new GMap(document.getElementById("map"));
  map.addControl(new GLargeMapControl());
  map.addControl(new GMapTypeControl());
  map.centerAndZoom(new GPoint(<%= @gmap[:center] %>), <%= @gmap[:zoom] %>);

  // Creates a marker whose info window displays the given number
  function createMarker(point, icon_image, text, url) {
    var icon = new GIcon(baseIcon);
    if (icon_image && icon_image.length > 0) {
      icon.image = icon_image;
    } else { 
      icon.image = "http://www.google.com/mapfiles/marker.png";
    } 

    var marker = new GMarker(point,icon);

        // Show this marker's index in the info window when it is clicked
        if (text.length > 0) {
          if (url.length > 0) {
              var html = "<a href='" + url + "'>" + text + "</a>";
            } else { 
              var html = text;
            } 
            html = '<div style="white-space:nowrap;">' + html + '</div>';

        GEvent.addListener(marker, "click", function() {
          marker.openInfoWindowHtml(html);
        });
      }
    return marker;
  }

    GEvent.addListener(map, "click", function(overlay, point) {
        var latLngStr = 'new GPoint(' + point.x + ', ' + point.y + ');';
        document.getElementById("message").innerHTML = latLngStr;
  });

  <%-
  n = 1
  for marker in @gmap[:markers]
      icon_image = image_path("marker#{n}")
    n += 1
  -%>
      var point = new GPoint(<%=marker[:point]%>);
      var marker = createMarker(point, "<%= icon_image %>", "<%= marker[:text] %>", "<%= marker[:url] %>");
      map.addOverlay(marker);
    <%-
    end
    -%>
 }
//]]>
</script>

main.rhtml

Create app/layout/main.rhtml with the following:

<html>
  <head>
    <title>RoR Demos</title>
  </head>

  <% if @body_tag %>
    <body <%= @body_tag %>>
  <% else %>
    <body>
  <% end %>
    <%= @content_for_layout %>
  </body>
</html>

Get Markers

Download at least the first image below as “marker1.png” and place it in public/images. If you are going to be using multiple markers on the same map, download the others too as “marker2.png” through “marker9.png”.

marker1.png marker2.png marker3.png marker4.png marker5.png marker6.png marker7.png marker8.png marker9.png

environment.rb

Next add this to your environment file config/environment.rb. Use your own Google Maps API Key in place of the one below:

MY_CONFIG = {
  :google_key => "ABQIAAAArk3wBzn5p0hIazFBq9_qyhRePOIxTiEEGKzrk_FoQ19c5nBl-BTqhex9dC6me07ldXQgj1wnfbXgng" 
}

Scaffold

The above files are the base files that can be used to show a map on any Rails page. To setup a test page, do the following.

Generate Controller

Create a controller in our demo app to show a map:

c:\rails\demo>ruby script\generate controller Map
    exists  app/controllers
exists app/helpers
create app/views/map exists test/functional
create app/controllers/map_controller.rb create test/functional/map_controller_test.rb create app/helpers/map_helper.rb

Edit map_controller.rb

Edit the app\controllers\map_controller.rb file to look like:

class MapController < ApplicationController

  layout 'main'

  def show
  end
end

Create show.rhtml

Finally, create app\views\map\show.rhtml:

<h1>Cardinal Venture Capital</h1>

<%= map :center => "-122.18172311782837, 37.453261881659074" %>

Hosts

Now, you are almost there. Just one more thing before testing your Google Map on Rails.

Edit your c:\windows\system32\drivers\etc\host file and add the line:

127.0.0.1 rordemo.com

If you have your own Google Maps key, then enter the URL that is associated with it instead of the “rordemo.com” above.

Results

If WEBrick is still running, restart it to pick up the new changes in environment.rb and then hit this URL:

http://rordemo.com:3000/map/show

Congratulations, you just put your first Google Map on Rails!

Map Parameters

In it’s simpliest form, use this in any rhtml page:

<%= map :center => "-122.18183,37.453977" %>

The :center parameter can be determined by adding a locator to a map, then clicking on any location and reading the coordinates underneath the map.

You can add a locator to any map using:

<%= map :center => "-122.18183,37.453977", :locator => true %>

Here are the parameters that can be used with maps:

:center => "-122.01686382293701, 37.31932181336203" 
:locater => true # When on, the coordinates will appear underneath the map when you click on it.
:width => "525"*
:height => "500"*
:zoom => "3" # Smaller numbers zoom in closer
:key => Abp123asdfu77asncZDSf # The Google maps key
:marker => "-122.02016830444336, 37.31850270698815" # Used to show the marker at a different location than :center.
:text => "Tri-Cities Little League" # The text to appear when you click on the marker
:url => "http://www.tricitiesbaseball.org" # The URL to go to when the text is clicked

Here is an example that shows two markers:

<%= map :width => "500", :height => "400", 
  :center => "-122.024846, 37.306761",
  :markers => [
    {:point => "-122.02517867088318, 37.306505188827586", 
     :text => "Meyerholz Field 1"},
    {:point => "-122.0241916179657, 37.30522511298032",
     :text => "Meyerholz Field 2"}] %>