Rails 3 and the HTML5 geolocation api

Let’s use the awesomeness of HTML5 to get the visitor location. In this article, we’ll see how to make an AJAX call with and without a link_to helper and how to retrieve the current location of the visitor using HTML5 and the plugin geokit-rails to lookup some data from Google with the location we got from the browser.

First thing firsts, we need an app and a controller. Classical routine:

$  rails new HTML5app
$  rails generate controller home index
$  rm public/index.html
$  vim config/routes   
    root :to => 'home#index'

edit application.js and add //= require jquery-ui

How to perform an AJAX call with rails 3.1

app/views/home/index.html

HTML5 location

app/controllers/home_controller.rb

class HomeController < ApplicationController
 def doSomethingWithGeoLocationVisitor
   @message = "test AJAX successful"
   respond_to do |format|
     format.js
   end
 end
end

app/views/home/index.html

<%= link_to "Get Location",{
    :controller=>"home",
    :action => 'doThingWithGeoLocationVisitor'},
  :remote=> true %>

Let’s replace our tag by a helper.

app/views/doSomehingWithGeoLocationVisitor.js.erb

$('#geoLocation').html("<%=h @message %>");

Get location from HTML5

A little search on Google gives us the jam. The jam is sweet. One function to get the position, a success and an error callback.

navigator.geolocation.getCurrentPosition(
     onSuccess,
     onError);

function onSuccess(position){...}
function onError(position){...}

In order to execute this code as soon as the page is loaded , we need to place our jam in a $(document).ready function.

So let’s separate the javascript in html5geolocation.js with the following.

app/assets/javascripts/html5geolocation.js

var myPosition = new Array();

$(document).ready(function() {
     navigator.geolocation.getCurrentPosition(
             onSuccess,
             onError, {
                 enableHighAccuracy: true,
                 timeout: 20000,
                 maximumAge: 120000
             }
     );
   function onSuccess(position) {
       myPosition[0] = position.coords.latitude;
       myPosition[1] = position.coords.longitude;
   }

    function onError(err) {
       var message;
       switch (err.code) {
       case 0:
         message = 'Unknown error: ' + err.message;
         break;
       case 1:
         message = 'You denied permission to retrieve a position.';
         break;
       case 2:
         message = 'The browser was unable to determine a position: ' + error.message;
         break;
       case 3:
         message = 'The browser timed out before retrieving the position.';
         break;
       }
    }

});

In the onError methods, we’ve got a basic error management and in the onSuccess method, we just fill a global JS variable.

Interact with rails with AJAX Get variable from JS Unfortunately, there is no helper to do that make an AJAX call with a Javascript variable. The trick is basically to change the link_to helper that we have seen before and replace it by some raw jQuery ajax call with a click handler.

app/assets/javascripts/html5geolocation.js

$(function($) {
   $("#getLocation").click(function() {
       $.ajax({
           url: "/home/doThingWithGeoLocationVisitor",
           data: 'lat=' + myPosition[0] +'&amp;lon=' + myPosition[1]
       })
   });
});

It would have been better to use a doThingWithGeoLocationVisitor_path by configuring the routes but some variables are not available in the assets, like for example render. So, if you change your controller name, don’t forget to fix your controller path in the url field.

Let’s query some public free API Now that we’ve got the AJAX call working and that we can retrieve the visitor’s location, let’s play with it with the plugin “geokit”.

To install the plugin geokit-rails: $rails plugin install git://github.com/andre/geokit-rails.git

Then we modify the file config/initializers/geokit_config.rb
by adding a personal Google Maps key.

Let’s retrieve some information with the location we got from the client.

app/controllers/home_controller.rb

class HomeController < ApplicationController

 def doThingWithGeoLocationVisitor
  lon = params[:lon]
  lat = params[:lat]

  info= Geokit::Geocoders::GoogleGeocoder.reverse_geocode lat+','+lon

  @message = info.full_address

  respond_to do |format|
     format.js
  end
 end
end

Voilà, now we’ve got easily some informations about the current visitor that we can treat on server-side. Enjoy now!

You can find the code of this article on my github right here:

https://github.com/nicocharlery/ArticleGeoHTML5

Licence  CC BY-SA 4.0
Mastodon