SlideShare a Scribd company logo
Geolocation on Rails
What is
geolocation?
identication of a real-world geographic
                location
identication of a real-world geographic
                location
                    =

        context
Brief history: early days


   many 1000s BC: smoke signals
   as early as 3200 BC: celestial navigation
   from 1000 BC: homing pigeons
   between 1100-1200 AD: the magnetic compass
Brief history: modern era


   early 1900s: radio triangulation
   1960s: satellite GPS
   1990s: automotive GPS navigation
Brief history: web era
   late 1990s: IP lookup
   mid 2000s: WiFi, GSM relevation
   2004: A-GPS on smartphones
Brief history: web era
   late 1990s: IP lookup
   mid 2000s: WiFi, GSM relevation
   2004: A-GPS on smartphones
Location-aware apps




 Later also Google, Facebook, and Twitter
Cool!
Let's join the party
Cool!
Let's join the party

      introducing:
 Stalk my Friends
Geolocation on Rails
1st step: display a map
    We'll use Google Maps

    # app/views/layouts/application.html.slim
    = javascript_include_tag https://maps.googleapis.com/maps/api/js


    // app/assets/javascripts/maps.js
    $(document).ready(function() {
        var mapOptions = {
            zoom: 8,
            center: new google.maps.LatLng(43.7710332, 11.2480006),
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };
        var map = new google.maps.Map($(’#map’)[0], mapOptions);
    });

git: google maps
2nd step: geolocate
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(
            function(p) {
                var latlng = new google.maps.LatLng(p.coords.latitude,
                                                    p.coords.longitude);
                $(’span#position’).text(latlng);
                if (myMarker) myMarker.setMap(null);
                myMarker = new google.maps.Marker(
                    {position: latlng, map: map, title: This is me}
                );
            },
            function(error) {
                alert(error.message);
            },
            {maximumAge: 600000}
        );
    }
    else { console.error(No HTML5? What are you using, IE6?); }
git: HTML5 geolocation
Geolocation API
supported by all current browers
location sources:
  1. GPS
  2. WiFi/Bluetooth MAC address
  3. GSM/CDMA cell IDs
  4. IP address
one-shot vs continuous
Geolocation on Rails
Geocode
 New feature: set the position manually.
Geocode
 New feature: set the position manually.
 We need to geocode the address.
Geocode
 New feature: set the position manually.
 We need to geocode the address.
 Several services:
     Google: 2.500 requests/day [1]
     Yahoo!: 50.000 requests/day [2]
     Bing: 50.000 requests/day [3]
     Nominatim: 1 request/second [4]
     FreeGeoIP: 1000 requests/hour [5]
     Geocoder.ca and Geocoder.us: ?
     many others...
Gems for geocode


   Geokit (deprecated, still lacks support for Rails 3) [7]
   Graticule [6]
   Geocoder [8]
Geocoder gem in action
 # Gemfile
 gem geocoder


 # map_controller.rb
 def geocode
   position = Geocoder.coordinates(params[:query])
   respond_to do |wants|
     wants.json { render :json = position }
   end
 end


 // applications.js
 $(’[data-action=cheat]’).click(function() {
     $.getJSON(’/geocode/’, {query: $(’#address’).val()}, map.cheat);
 });    git: geocoding
Awesome! We have a user position.
    Now to interact with other users we need:
store lat/long (and address, eventually) in a DB
query the DB for nearby points
1st approach: D.I.Y. I
 # migration
 class CreateUsers  ActiveRecord::Migration
   def change
     create_table :users do |t|
       t.string :name
       t.float :latitude
       t.float :longitude
       t.string :address

       t.timestamps
     end
   end
 end
1st approach: D.I.Y. II

 # app/controllers/users_controller.rb
 class UsersController  ApplicationController
   respond_to :json

   def index
     @users = @user.nearbys(params[:radius])
     respond_with @users
   end
 end
1st approach: D.I.Y. III

 # app/models/user.rb
 class User  ActiveRecord::Base
   attr_accessible :address, :latitude, :longitude, :name

   def nearbys(radius)
   # ... oh s@#!t
   end
 end
Let’s do some math

 Earth is a sphere: coordinates are in degree, distance is in
 meters.
 Solve the second (inverse) geodetic problem
 Given two points, determine the azimuth and length of the
 line (straight line, arc or geodesic) that connects them. [9]

     spherical model: Haversine formula (approximation)
     oblate spheroid model: Vincenty's formulae
Haversine formula

  d = 2r arcsin   h(φ2 − φ1 ) + cos(φ1 ) cos(φ2 ) h(ψ2 − ψ1 )                   (1)


    =2 r arcsin   sin2
                         φ2 − φ1
                            2
                                    + cos(φ1 ) cos(φ2 ) sin2
                                                                ψ2 − ψ1
                                                                   2
                                                                                (2)



 where:
     h() is the haversine function: h(θ) = sin(θ/2)              2
                                                                     =   1−cos(θ)
                                                                            2

     d distance
     r radius of the sphere (6371.0 km)
     φ1 , φ2 latitude of point 1 and latitude of point 2
     ψ1 , ψ2 longitude of point 1 and longitude of point 2
Geocoder to the rescue!
    # app/models/user.rb
    geocoded_by :address
    reverse_geocoded_by :latitude, :longitude
    after_validation :reverse_geocode


    # app/controllers/users_controller.rb
    def index
      @users = @user.nearbys(params[:radius])
      respond_with @users
    end

    Geocoder implements the Haversine formula
    directly in the SQL query.
git: Geocoder backend
Geocoder goodies
 # Nearest point
 user = User.near(Firenze, 50, :order = distance).first

 # distance from arbitrary point to user
 user.distance_from([40.714, 11.234])

 # Find the bearing (direction) between places
 bearing = user.bearing_to(Paris, France)
 Geocoder::Calculations.compass_point(bearing)
   = NW

 # find the geographic center (aka center of gravity)
 polygon = [user1, user2, [40.22,-73.99], user4]
 Geocoder::Calculations.geographic_center(polygon)
   = [35.14968, -90.048929]
Geocoder considerations

 Pros
   simple and easy to use

 Cons
   only circle areas
   SLOW (depends on the DBMS)
2nd approach: PostGIS




 PostGIS [10] is an extention for PostgreSQL that adds
 support for geographic objects.
 Alternatives are:
     MySQL: implements the datatype geometry
     Sqlite: with SpatiaLite extension
PostGIS setup
 # install on a ubuntu box
 sudo apt-get install postgresql-9.1-postgis


 # prepare the db
 createdb template_postgis
 createlang plpgsql template_postigs
 psql -Upostgres -d template_postgis -f   [...]/postgis.sql
 psql -Upostgres -d template_postgis -f   [...]/spatial_ref_sys.sql
 psql -Upostgres -d template_postgis -f   [...]/postgis_comments.sql
 # inside postgres console
 UPDATE pg_database SET datistemplate =   TRUE
 WHERE datname = ’template_postgis’;
PostGIS features

 PostGIS follows the OpenGIS Simple Features
 Specication for SQL [11]
     data types for points, linestrings, polygons, multipoints,
     multilinestrings, multipolygons and geometrycollections
     functions for measurement like area, distance, length
     and perimeter
     spatial indexes for high speed spatial querying
PostGIS with Ruby


 We'll use gem activerecord-postgis-adapter
 to integrate postgis data types in ActiveRecord.
ActiveRecord PostGIS
 # config/database.yml
 development:
   adapter: postgis
   encoding: unicode
   database: stalk_my_friends
   pool: 5
   username: nebirhos
   template: template_postgis


 # migration
 add_column :users, :position, :point, :geographic = true
 add_index :users, :position, :spatial = true


 # app/models/user.rb
 self.rgeo_factory_generator = RGeo::Geographic.simple_mercator_factory
 # SRID 4326, used by Google Maps
PostGIS query


     # app/models/user.rb
     def nearbys(radius)
       radius = radius.to_i*1000
       User.where( ST_Distance(position, ?, false) = ? ,
                   position, radius ).where(id  ?, id)
     end




git: master
Questions?
Thanks for watching!

 Francesco Disperati | @nebirhos
                http://nebirhos.com

 Source code of the demo app available at
 https://github.com/nebirhos/stalk-my-friends


    Special thanks to Cantiere Creativo and Silvia Shell
Random stuff cited
   Google Geocode API        https://developers.google.com/maps/documentation/geocoding/

   Yahoo! PlaceFinder      http://developer.yahoo.com/geo/placefinder/guide/responses.html

   Bing API    http://msdn.microsoft.com/en-us/library/ff701715.aspx

   Nominatim     http://wiki.openstreetmap.org/wiki/Nominatim

   FreeGeoIP    http://github.com/fiorix/freegeoip/blob/master/README.rst

   Graticule   http://graticule.rubyforge.org/

   Geokit   http://geokit.rubyforge.org/

   Geocoder    http://www.rubygeocoder.com/

   Geodesy on Wikipedia       http://en.wikipedia.org/wiki/Geodesy

   PostGIS   http://postgis.refractions.net/

   OpenGIS     http://www.opengeospatial.org/standards/sfs

   PostGIS ActiveRecord Adapter            https://github.com/dazuma/activerecord-postgis-adapter

More Related Content

Similar to Geolocation on Rails (20)

PDF
Geographic Computation in Perl
Ian Kluft
 
ZIP
Geohex at Off4g2009
Tadayasu Sasada
 
PDF
Geokit In Social Apps
Paul Jensen
 
KEY
Handling Real-time Geostreams
Raffi Krikorian
 
KEY
Handling Real-time Geostreams
guest35660bc
 
PDF
Geographical Data Management for Web Applications
Symeon Papadopoulos
 
PDF
Where20 2008 Ruby Tutorial
Shoaib Burq
 
PDF
Geohex v2 at GMS_nagoya
Tadayasu Sasada
 
KEY
Mapping Flatland: Using MongoDB for an MMO Crossword Game (GDC Online 2011)
Grant Goodale
 
PDF
The Geo-aware Parent
Matt Machell
 
PDF
About GeoHex
Tadayasu Sasada
 
PPTX
Geopy module in python
Ashmita Dhakal
 
PPTX
Where in the world
Marcus Deglos
 
PDF
Introduction to Geo Technologies
Christian Heilmann
 
PDF
Introduction to Geo hacking with (amongst others) Yahoo Technology.
Christian Heilmann
 
PDF
Interview with Developer Jose Luis Arenas regarding Google App Engine & Geosp...
Rif Kiamil
 
PPTX
Geopy Module in Python
RabinaTwayana
 
PDF
GeoDjango in a nutshell
Django Stars
 
KEY
Geospatial Indexing and Querying with MongoDB
Grant Goodale
 
PDF
PostGIS on Rails
Matt Nemenman
 
Geographic Computation in Perl
Ian Kluft
 
Geohex at Off4g2009
Tadayasu Sasada
 
Geokit In Social Apps
Paul Jensen
 
Handling Real-time Geostreams
Raffi Krikorian
 
Handling Real-time Geostreams
guest35660bc
 
Geographical Data Management for Web Applications
Symeon Papadopoulos
 
Where20 2008 Ruby Tutorial
Shoaib Burq
 
Geohex v2 at GMS_nagoya
Tadayasu Sasada
 
Mapping Flatland: Using MongoDB for an MMO Crossword Game (GDC Online 2011)
Grant Goodale
 
The Geo-aware Parent
Matt Machell
 
About GeoHex
Tadayasu Sasada
 
Geopy module in python
Ashmita Dhakal
 
Where in the world
Marcus Deglos
 
Introduction to Geo Technologies
Christian Heilmann
 
Introduction to Geo hacking with (amongst others) Yahoo Technology.
Christian Heilmann
 
Interview with Developer Jose Luis Arenas regarding Google App Engine & Geosp...
Rif Kiamil
 
Geopy Module in Python
RabinaTwayana
 
GeoDjango in a nutshell
Django Stars
 
Geospatial Indexing and Querying with MongoDB
Grant Goodale
 
PostGIS on Rails
Matt Nemenman
 

Recently uploaded (20)

PDF
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
PDF
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
PPTX
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
PDF
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
PDF
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
PDF
July Patch Tuesday
Ivanti
 
PDF
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
PDF
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
PPTX
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
PDF
Transcript: New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
PDF
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
DOCX
Python coding for beginners !! Start now!#
Rajni Bhardwaj Grover
 
DOCX
Cryptography Quiz: test your knowledge of this important security concept.
Rajni Bhardwaj Grover
 
PDF
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
PPTX
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
PDF
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PPTX
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
PDF
What Makes Contify’s News API Stand Out: Key Features at a Glance
Contify
 
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
July Patch Tuesday
Ivanti
 
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
Transcript: New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
Python coding for beginners !! Start now!#
Rajni Bhardwaj Grover
 
Cryptography Quiz: test your knowledge of this important security concept.
Rajni Bhardwaj Grover
 
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
What Makes Contify’s News API Stand Out: Key Features at a Glance
Contify
 
Ad

Geolocation on Rails

  • 3. identication of a real-world geographic location
  • 4. identication of a real-world geographic location = context
  • 5. Brief history: early days many 1000s BC: smoke signals as early as 3200 BC: celestial navigation from 1000 BC: homing pigeons between 1100-1200 AD: the magnetic compass
  • 6. Brief history: modern era early 1900s: radio triangulation 1960s: satellite GPS 1990s: automotive GPS navigation
  • 7. Brief history: web era late 1990s: IP lookup mid 2000s: WiFi, GSM relevation 2004: A-GPS on smartphones
  • 8. Brief history: web era late 1990s: IP lookup mid 2000s: WiFi, GSM relevation 2004: A-GPS on smartphones
  • 9. Location-aware apps Later also Google, Facebook, and Twitter
  • 11. Cool! Let's join the party introducing: Stalk my Friends
  • 13. 1st step: display a map We'll use Google Maps # app/views/layouts/application.html.slim = javascript_include_tag https://maps.googleapis.com/maps/api/js // app/assets/javascripts/maps.js $(document).ready(function() { var mapOptions = { zoom: 8, center: new google.maps.LatLng(43.7710332, 11.2480006), mapTypeId: google.maps.MapTypeId.ROADMAP }; var map = new google.maps.Map($(’#map’)[0], mapOptions); }); git: google maps
  • 14. 2nd step: geolocate if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( function(p) { var latlng = new google.maps.LatLng(p.coords.latitude, p.coords.longitude); $(’span#position’).text(latlng); if (myMarker) myMarker.setMap(null); myMarker = new google.maps.Marker( {position: latlng, map: map, title: This is me} ); }, function(error) { alert(error.message); }, {maximumAge: 600000} ); } else { console.error(No HTML5? What are you using, IE6?); } git: HTML5 geolocation
  • 15. Geolocation API supported by all current browers location sources: 1. GPS 2. WiFi/Bluetooth MAC address 3. GSM/CDMA cell IDs 4. IP address one-shot vs continuous
  • 17. Geocode New feature: set the position manually.
  • 18. Geocode New feature: set the position manually. We need to geocode the address.
  • 19. Geocode New feature: set the position manually. We need to geocode the address. Several services: Google: 2.500 requests/day [1] Yahoo!: 50.000 requests/day [2] Bing: 50.000 requests/day [3] Nominatim: 1 request/second [4] FreeGeoIP: 1000 requests/hour [5] Geocoder.ca and Geocoder.us: ? many others...
  • 20. Gems for geocode Geokit (deprecated, still lacks support for Rails 3) [7] Graticule [6] Geocoder [8]
  • 21. Geocoder gem in action # Gemfile gem geocoder # map_controller.rb def geocode position = Geocoder.coordinates(params[:query]) respond_to do |wants| wants.json { render :json = position } end end // applications.js $(’[data-action=cheat]’).click(function() { $.getJSON(’/geocode/’, {query: $(’#address’).val()}, map.cheat); }); git: geocoding
  • 22. Awesome! We have a user position. Now to interact with other users we need: store lat/long (and address, eventually) in a DB query the DB for nearby points
  • 23. 1st approach: D.I.Y. I # migration class CreateUsers ActiveRecord::Migration def change create_table :users do |t| t.string :name t.float :latitude t.float :longitude t.string :address t.timestamps end end end
  • 24. 1st approach: D.I.Y. II # app/controllers/users_controller.rb class UsersController ApplicationController respond_to :json def index @users = @user.nearbys(params[:radius]) respond_with @users end end
  • 25. 1st approach: D.I.Y. III # app/models/user.rb class User ActiveRecord::Base attr_accessible :address, :latitude, :longitude, :name def nearbys(radius) # ... oh s@#!t end end
  • 26. Let’s do some math Earth is a sphere: coordinates are in degree, distance is in meters. Solve the second (inverse) geodetic problem Given two points, determine the azimuth and length of the line (straight line, arc or geodesic) that connects them. [9] spherical model: Haversine formula (approximation) oblate spheroid model: Vincenty's formulae
  • 27. Haversine formula d = 2r arcsin h(φ2 − φ1 ) + cos(φ1 ) cos(φ2 ) h(ψ2 − ψ1 ) (1) =2 r arcsin sin2 φ2 − φ1 2 + cos(φ1 ) cos(φ2 ) sin2 ψ2 − ψ1 2 (2) where: h() is the haversine function: h(θ) = sin(θ/2) 2 = 1−cos(θ) 2 d distance r radius of the sphere (6371.0 km) φ1 , φ2 latitude of point 1 and latitude of point 2 ψ1 , ψ2 longitude of point 1 and longitude of point 2
  • 28. Geocoder to the rescue! # app/models/user.rb geocoded_by :address reverse_geocoded_by :latitude, :longitude after_validation :reverse_geocode # app/controllers/users_controller.rb def index @users = @user.nearbys(params[:radius]) respond_with @users end Geocoder implements the Haversine formula directly in the SQL query. git: Geocoder backend
  • 29. Geocoder goodies # Nearest point user = User.near(Firenze, 50, :order = distance).first # distance from arbitrary point to user user.distance_from([40.714, 11.234]) # Find the bearing (direction) between places bearing = user.bearing_to(Paris, France) Geocoder::Calculations.compass_point(bearing) = NW # find the geographic center (aka center of gravity) polygon = [user1, user2, [40.22,-73.99], user4] Geocoder::Calculations.geographic_center(polygon) = [35.14968, -90.048929]
  • 30. Geocoder considerations Pros simple and easy to use Cons only circle areas SLOW (depends on the DBMS)
  • 31. 2nd approach: PostGIS PostGIS [10] is an extention for PostgreSQL that adds support for geographic objects. Alternatives are: MySQL: implements the datatype geometry Sqlite: with SpatiaLite extension
  • 32. PostGIS setup # install on a ubuntu box sudo apt-get install postgresql-9.1-postgis # prepare the db createdb template_postgis createlang plpgsql template_postigs psql -Upostgres -d template_postgis -f [...]/postgis.sql psql -Upostgres -d template_postgis -f [...]/spatial_ref_sys.sql psql -Upostgres -d template_postgis -f [...]/postgis_comments.sql # inside postgres console UPDATE pg_database SET datistemplate = TRUE WHERE datname = ’template_postgis’;
  • 33. PostGIS features PostGIS follows the OpenGIS Simple Features Specication for SQL [11] data types for points, linestrings, polygons, multipoints, multilinestrings, multipolygons and geometrycollections functions for measurement like area, distance, length and perimeter spatial indexes for high speed spatial querying
  • 34. PostGIS with Ruby We'll use gem activerecord-postgis-adapter to integrate postgis data types in ActiveRecord.
  • 35. ActiveRecord PostGIS # config/database.yml development: adapter: postgis encoding: unicode database: stalk_my_friends pool: 5 username: nebirhos template: template_postgis # migration add_column :users, :position, :point, :geographic = true add_index :users, :position, :spatial = true # app/models/user.rb self.rgeo_factory_generator = RGeo::Geographic.simple_mercator_factory # SRID 4326, used by Google Maps
  • 36. PostGIS query # app/models/user.rb def nearbys(radius) radius = radius.to_i*1000 User.where( ST_Distance(position, ?, false) = ? , position, radius ).where(id ?, id) end git: master
  • 38. Thanks for watching! Francesco Disperati | @nebirhos http://nebirhos.com Source code of the demo app available at https://github.com/nebirhos/stalk-my-friends Special thanks to Cantiere Creativo and Silvia Shell
  • 39. Random stuff cited Google Geocode API https://developers.google.com/maps/documentation/geocoding/ Yahoo! PlaceFinder http://developer.yahoo.com/geo/placefinder/guide/responses.html Bing API http://msdn.microsoft.com/en-us/library/ff701715.aspx Nominatim http://wiki.openstreetmap.org/wiki/Nominatim FreeGeoIP http://github.com/fiorix/freegeoip/blob/master/README.rst Graticule http://graticule.rubyforge.org/ Geokit http://geokit.rubyforge.org/ Geocoder http://www.rubygeocoder.com/ Geodesy on Wikipedia http://en.wikipedia.org/wiki/Geodesy PostGIS http://postgis.refractions.net/ OpenGIS http://www.opengeospatial.org/standards/sfs PostGIS ActiveRecord Adapter https://github.com/dazuma/activerecord-postgis-adapter