Geocoding typically refers to the transformation process of addresses and places to coordinates.
# Example Geocoder.coordinates("25 Main St, Cooperstown, NY") => [42.700149, -74.922767]
It is sometimes called forward geocoding whereas Reverse geocoding uses geographic coordinates to find a description of the location, most typically a postal address or place name.
In Rails we are going to use
Geocoder [Reference Inspired from Original Doc]
Geocoder is a complete geocoding solution for Ruby. With Rails it adds geocoding (by street or IP address), reverse geocoding (finding street address based on given coordinates), and distance queries. It’s as simple as calling
geocode on your objects, and then using a scope like
For geocoding your model must provide a method that returns an address. This can be a single attribute, but it can also be a method that returns a string assembled from different attributes (eg:
Next, your model must tell Geocoder which method returns your object’s geocodable address:
geocoded_by :full_street_address # can also be an IP address after_validation :geocode # auto-fetch coordinates
For reverse geocoding, tell Geocoder which attributes store latitude and longitude:
reverse_geocoded_by :latitude, :longitude after_validation :reverse_geocode # auto-fetch address
Request Geocoding by Zip-Code
geocoded_by :zip_code reverse_geocoded_by :latitude, :longitude do |obj, results| if geo = results.first obj.state = geo.state obj.city = geo.city end end
Request Geocoding by IP Address
safe_location methods to the standard
Rack::Request object so you can easily look up the location of any HTTP request by IP address. For example, in a Rails controller or a Sinatra app:
# returns Geocoder::Result object result = request.location
location method is vulnerable to trivial IP address spoofing via HTTP headers. If that’s a problem for your application, use
Location-Aware Database Queries
For geocoded objects you can do things like this:
if obj.geocoded? obj.nearbys(30) # other objects within 30 miles obj.distance_from([40.714,-100.234]) # distance from arbitrary point to object obj.bearing_to("Paris, France") # direction from object to arbitrary point end
At class level
Venue.near('Omaha, NE, US', 20) # venues within 20 miles of Omaha Venue.near([40.71, -100.23], 20) # venues within 20 miles of a point Venue.near([40.71, -100.23], 20, :units => :km) # venues within 20 kilometres of a point Venue.geocoded # venues with coordinates Venue.not_geocoded # venues without coordinates
Venue is a model in which
geocoder is initialized.
Distance and Bearing
When you run a location-aware query the returned objects have two attributes added to them (only w/ ActiveRecord):
obj.distance– number of miles from the search point to this object
obj.bearing– direction from the search point to this object
Bearing is given as a number of clockwise degrees from due north, for example:
0– due north
180– due south
90– due east
270– due west
359.9– almost due north
You can convert these numbers to compass point names by using the utility method provided:
Geocoder::Calculations.compass_point(355) # => "N" Geocoder::Calculations.compass_point(45) # => "NE" Geocoder::Calculations.compass_point(208) # => "SW"
when using SQLite
bearing values are provided for interface consistency only. They are not very accurate.
To calculate accurate distance and bearing with SQLite or MongoDB:
obj.distance_to([43.9,-98.6]) # distance from obj to point obj.bearing_to([43.9,-98.6]) # bearing from obj to point obj.bearing_from(obj2) # bearing from obj2 to obj
bearing_from/to methods take a single argument which can be: a
[lat,lon] array, a geocoded object, or a geocodable address (string). The
distance_from/to methods also take a units argument (
:nm for nautical miles).
Search in Box rather than Circle
You can also look within a square rather than a radius (circle) by using the
distance = 20 center_point = [40.71, 100.23] box = Geocoder::Calculations.bounding_box(center_point, distance) Venue.within_bounding_box(box)
- Note, however, that returned results do not include
- Note that
#nearperforms both bounding box and radius queries for speed.
Search in Donut or Ring
You can also specify a minimum radius (if you’re using ActiveRecord and not Sqlite) to constrain the lower bound (ie. think of a donut, or ring) by using the
box = Geocoder::Calculations.bounding_box(center_point, distance, :min_radius => 10.5)
Auto Assignment of decoded info
So far we have looked at shortcuts for assigning geocoding results to object attributes.
However, if you need to do something fancy you can skip the auto-assignment by providing a block (takes the object to be geocoded and an array of
Geocoder::Result objects) in which you handle the parsed geocoding result any way you like, for example:
reverse_geocoded_by :latitude, :longitude do |obj,results| if geo = results.first obj.city = geo.city obj.zipcode = geo.postal_code obj.country = geo.country_code end end after_validation :reverse_geocode
result, provides the following data:
result.coordinates– array of the above two in the form of