http://www.developer.com/

Back to article

Adding Google Maps To Your Rails Applications


July 8, 2008

In the months following publication of the final part of the very popular series on integrating Google Maps into PHP applications, I've spent quite a bit of time working with another popular Web technology: Ruby on Rails. As it turns out, Rails developers have been hard at work creating a few amazing plugins capable of adding powerful mapping capabilities to your applications. In this new series, I'll introduce you to these powerful plugins, showing you a number of tips and tricks along the way.

I'll presume you're familiar with mapping fundamentals, including the basic ideas surrounding the Google mapping API syntax. If you haven't had the opportunity to experiment with the API, take some time to read this tutorial before continuing.

Introducing the YM4R/GM Plugin

Although there's nothing preventing you from linking to Google's mapping JavaScript API and referencing the library directly from your views, jumping between Ruby/Rails syntax and JavaScript can quickly become a tedious affair. The YM4R/GM plugin remedies this issue nicely, abstracting the API calls through Ruby's familiar object-oriented syntax. With it you can do everything from render simple maps to build complex maps complete with custom markers, information windows, and clusters for facilitating the rendering of large numbers of markers.

Installing and Configuring YM4R/GM

To install the YM4R/GM plugin, execute the following command from your project directory:

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

YM4R/GM manages the Google API keys within a file named gmaps_api_key.yml, found in the project's config directory. The developers save you the trouble of having to create your own API key for local testing purposes by including an API key that has already been tied to http://localhost:3000. However, if you're testing on a different host, you'll first need to create an API key and add it to this file (instructions for creating a key are provided in the aforementioned introductory tutorial).

Creating Your First Map

To get acquainted with YM4R/GM's syntax, you can begin by creating the map displayed in Figure 1.

Figure 1: Centering the map over Youngstown, Ohio

As is standard Rails practice, you'll use the controller method to define the map and its features, and the view to render the results. In the following example, you'll define a map in the index controller's index action, complete with a pan/zoom control but minus the map type selector:

def index
   # Create a new map object, also defining the div ("map") 
   # where the map will be rendered in the view
   @map = GMap.new("map")
   # Use the larger pan/zoom control but disable the map type
   # selector
   @map.control_init(:large_map => true,:map_type => false)
   # Center the map on specific coordinates and focus in fairly
   # closely
   @map.center_zoom_init([41.023849,-80.682053], 10)
end

Next, in the index action's corresponding view, add the following code:

<html>
   <head>
      <title>Test</title>
      <%= GMap.header %>
      <%= @map.to_html %>
   </head>
   <body>
      <%= @map.div(:width => 400, :height => 300) %>
   </body>
</html>

The GMap.header call will output references to both the Google Maps API and YM4R/GM JavaScript libraries. The @map.to_html call outputs JavaScript code generated by YM4R/GM according to the specifications set forth in the action. Finally, the @map.div call outputs the map to a div as specified in the action's GMap.new call.

Also, you'll see that the map dimensions are defined in the view rather than the controller. This is keeping with the convention of separating application logic and design; the view designer can choose any dimension he pleases; the map will simply fill to the desired size. The initial zoom level is, however, defined in the controller, although the user can easily subsequently adjust the zoom using the control.

Changing the Map Type Selector Language

Setting the control_init() method's :map_type parameter to true will give the user the ability to switch among Google's three different map types (map, satellite, hybrid). Google makes it trivial to change the language in which these type prompts are displayed by passing the :hl option to the static header() method call. Nine languages are supported (Basque - eu, Catalan - ca, French - fr, Galician - gl, German - de, Italian - it, Japanese - jp, and Spanish - es), including the English default. For instance, setting :hl to it will produce the map displayed in Figure 2.

Figure 2: Displaying map controls in the Italian language

In case you're wondering exactly what the header() call would look like, I'll reproduce it here:

<%= GMap.header(:hl=>'it') %>

Adding Markers and Information Windows

The maps displayed in Figures 1 and 2 put you in close proximity of a specific location, but without some context the practical nature of the map really ends there. For instance, in this example you'd never actually know I've centered the map over one of Youngstown, Ohio's famous pizzerias, namely Ianazone's. To pinpoint the location, you need the ability to create a marker that identifies the location. This is easily done by creating a GMarker object, and then passing that marker to the overlay_init() method. To add the Ianazone's marker, add the following two lines to the end of the index action:

ianazones = GMarker.new([41.023849,-80.682053])
@map.overlay_init(ianazones)

Executing the action anew produces the map displayed in Figure 3.

Figure 3: Adding a marker to the map

Adding Multiple Markers

Adding multiple markers doesn't require knowledge of any additional methods; just create multiple markers and add each to the map using overlay_init(). For instance, the following code will add both Ianazone's and Belleria Pizza to the map, producing the map displayed in Figure 4:

ianazones = GMarker.new([41.023849,-80.682053])
@map.overlay_init(ianazones)

belleria = GMarker.new([41.111141,-80.641281])
@map.overlay_init(belleria)

Figure 4: Adding multiple markers to the map

If you're planning on working with large numbers of markers, look into YM4R/GM's Clusterer class. Clusterer helps manage the display of large numbers of markers by displaying only those that are explicitly visible from a specific zoom level, rather than those that are otherwise piled atop one another due to close proximity. A later article in this series will address this matter in some detail, so stay tuned.

Adding Information Windows

Figure 4 is clear proof you're getting somewhere, showing users where to find the best pizza in town. However, which icon points to Ianazone's, and which to Belleria's? You can rectify this problem by modifying the GMarker calls to include additional information that will display in an information window should the user click on the marker. The following code will add pizzeria names and mailing addresses to each window:

ianazones_address = "Ianazone's<br />8590 Glenwood Ave<br />
   Boardman, OH 44512"

ianazones = GMarker.new([41.023849,-80.682053],
  :title => "Ianazone's Pizza", 
  :info_window => "#{ianazones_address}")
@map.overlay_init(ianazones)

belleria_address = "Belleria's<br />789 Wick Ave<br />Youngstown,
   OH 44505"

belleria = GMarker.new([41.111141,-80.641281],
  :title => "Belleria's", 
  :info_window => "#{belleria_address}")
@map.overlay_init(belleria)

Figure 5: Adding an information window to the map

Notice the use of <br /> tags in the information window message to separate each line. You're free to use any valid HTML markup you please to dress up the format.

Changing the Default Icon

The default red teardrop icon is okay for a standard map, but what if you wanted to spruce things up a bit? With a bit of additional programming and some patience, you can change the default icon to one more fitting of your website's purpose. For instance, Figure 6 displays a map using a custom pizza box icon.

Figure 6: Adding an information window to the map

As you can see below, the code is fairly straightforward. First, you need to define the custom icon by creating a GIcon object, and defining the icon and corresponding shadow icon location. To offset the shadow icon, you'll see I'm stretching it an additional five pixels wide to achieve the shadow's casting effect. Next, you need to define the icon anchor relative to the marker coordinates, and finally the offset location of the informational window that will appear when the icon is clicked. Finally, you give the icon a name, in this case, pizza_icon, and define it as a variable.

Any time you'd like to subsequently use the custom icon, just pass that icon name into the GMarker declaration, as is shown below.

@map.icon_global_init(GIcon.new(:image => "/images/pizza.png",
   :shadow => "/images/pizza-shadow.png",
   :shadow_size => GSize.new(37,32),
   :icon_anchor => GPoint.new(7,7),
   :info_window_anchor => GPoint.new(9,2)), "pizza_icon")

pizza_icon = Variable.new("pizza_icon")

ianazones_address = "Ianazone's<br />8590 Glenwood Ave<br />
   Boardman, OH 44512"

ianazones = GMarker.new([41.023849,-80.682053],
   :icon => pizza_icon,
   :title => "Ianazone's Pizza",
   :info_window => "#{ianazones_address}")

@map.overlay_init(ianazones)

You might have noted I mentioned patience is a requirement when creating custom icons. This is because you'll need to spend some time creating the icon unless you can find one with an appropriate usage policy, and then experiment with shadow opacity and offset until the desired affect is achieved. Once complete, though, your users will marvel at your attention to detail!

Where to From Here?

Hopefully, this introductory tutorial leaves your mind racing regarding new possibilities for your Rails applications! This is just a sampling of things to come, though; in future installments, you're going to stretch the capabilities of Rails and the Google Maps API to their limits, so check back regularly for the latest updates!

About the Author

W. Jason Gilmore is a freelance developer, consultant, and technical writer. He's the author of several books, including the best-selling Beginning PHP and MySQL: From Novice to Professional, Third Edition (Apress, 2008. 1,080pp.).

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date