= Geocoder

Geocoder adds object geocoding and database-agnostic distance calculations to Ruby on Rails. It's as simple as calling <tt>fetch_coordinates!</tt> on your objects, and then using a named scope like <tt>near("Billings, MT")</tt>.

Geocoder does not rely on proprietary database functions so finding geocoded objects in a given area is easily done using out-of-the-box MySQL or even SQLite.


== 1. Install

Install either as a plugin:

  script/plugin install git://github.com/alexreisner/geocoder.git

or as a gem:

  # add to config/environment.rb:
  config.gem "rails-geocoder", :lib => "geocoder", :source => "http://gemcutter.org/"
  
  # at command prompt:
  sudo rake gems:install


== 2. Configure

First, you must get a Google Maps API key (to get one go to http://code.google.com/apis/maps/signup.html) and store it in a constant:

  # eg, in config/initializers/google_maps.rb
  GOOGLE_MAPS_API_KEY = "..."

Add +latitude+ and +longitude+ columns to your model:

  script/generate migration AddLatitudeAndLongitudeToModel \
    latitude:float \
    longitude:float
  rake db:migrate

Then tell your model about it:

  geocoded_by :address                  # attribute/method to use for geocoding
  after_validation :fetch_coordinates!  # fetch and assign coordinates before saving

You do not have to use the +latitude+ and +longitude+ column names. See "More On Configuration" below for details.


== 3. Use

Assuming +Venue+ is a geocoded model, it has the following named scopes:

  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.geocoded                     # venues with coordinates
  Venue.not_geocoded                 # venues without coordinates

Assuming +obj+ has a valid string for its +location+:

  obj.fetch_coordinates              # returns coordinates [lat, lon]
  obj.fetch_coordinates!             # also writes coordinates to object

Assuming +obj+ is geocoded (has latitude and longitude):

  obj.nearbys(30)                    # other objects within 30 miles
  obj.distance_to(40.714, -100.234)  # distance to arbitrary point

Some utility methods are also available:

  # distance (in miles) between Eiffel Tower and Empire State Building
  Geocoder.distance_between( 48.858205,2.294359,  40.748433,-73.985655 )
  
  # look up coordinates of some location (like searching Google Maps)
  Geocoder.fetch_coordinates("25 Main St, Cooperstown, NY")


== More On Configuration

You are not stuck with using the +latitude+ and +longitude+ database column names for storing coordinates. For example, to use +lat+ and +lon+:

  geocoded_by :address, :latitude  => :lat, :longitude => :lon

The string to use for geocoding can be anything you'd use to search Google Maps. For example, any of the following are acceptable:

  714 Green St, Big Town, MO
  Eiffel Tower, Paris, FR
  Paris, TX, US

If your model has +address+, +city+, +state+, and +country+ attributes you might do something like this:

  geocoded_by :location

  def location
    [address, city, state, country].compact.join(', ')
  end


Please see the code for more methods and detailed information about arguments (eg, working with kilometers).


== To-do List

* rake task for geocoding all non-geocoded objects
* <tt>install.rb</tt> should do some setup when installed as a plugin


Copyright (c) 2009 Alex Reisner, released under the MIT license