Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Easier latitudes and longitudes on forms (and validation in model) for Rails 2.3.

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 lib
Octocat-spinner-32 test
Octocat-spinner-32 .gitignore
Octocat-spinner-32 .rbenv-version
Octocat-spinner-32 Gemfile
Octocat-spinner-32 MIT-LICENSE
Octocat-spinner-32 README.md
Octocat-spinner-32 Rakefile
Octocat-spinner-32 geo_tools.gemspec
README.md

GeoTools

Caveat

This code is quite old. I wouldn't do things this way now, but it's in production and it works.

Compatibility

Works on Ruby 1.8+ and 1.9+.

Designed for Rails 2.3.

Overview

You have lots of plugin choices if you want to geocode North American addresses, or find all the locations near somewhere. But few help you with forms and validation.

This plugin does four things:

  • Adds latitude_field and longitude_field form helpers to Rails' default form builder.
  • Lets your model acts_as_location, to work seamlessly with the form helpers.
  • Validates the location data entered on the form and in the database.
  • Gives you a within named scope to find all lcoations within a given bounding box, such as you would have on a Google map.

Assumptions

  • Any model that acts_as_location has integers defined for each component of the latitude and longitude:

    # In your model's migration's self.up method:
    create_table :thingies do |t|
      # Your model's various fields.
      t.string :name
      t.timestamps
      ...
    
      # Stuff GeoTools needs:
      t.integer :latitude_degrees,  :latitude_minutes,  :latitude_decimal_minutes, :latitude_decimal_minutes_width
      t.string  :latitude_hemisphere
      t.integer :longitude_degrees, :longitude_minutes, :longitude_decimal_minutes, :longitude_decimal_minutes_width
      t.string  :longitude_hemisphere
    end
    

    Storing the components separately like this avoids the round-trip rounding errors you get when using floating point numbers. If you need a floating point representation in the database, for example to use a mapping plugin, simply add an after_update callback to your model to write the float value to the database.

  • A latitude should be entered on a form like this:

    xx <degree symbol> yy <decimal point> zz h
    

    where:

    xx is degrees (0 <= integer <= 90; maximum length of 2 digits)
    yy is minutes (0 <= integer <= 59; maximum length of 2 digits; optional; defaults to 0)
    zz is decimal-minutes (0 <= integer <= 99; maximum length of 2 digits; optional; defaults to 0)
    h is hemisphere ('N' or 'S')
    

    Note with decimal minutes 2, 20 and 200000 are equivalent. This is because 3.2, 3.20 and 3.200000 are equivalent.

  • Similarly, a longitude should be entered on a form like this:

    xxx <degree symbol> yy <decimal point> zz h
    

    where:

    xxx is degrees (0 <= integer <= 180; maximum length of 3 digits)
    yy is minutes (0 <= integer <= 59; maximum length of 2 digits; optional; defaults to 0)
    zz is decimal-minutes (0 <= integer <= 99; maximum length of 2 digits; optional; defaults to 0)
    h is hemisphere ('E' or 'W')
    

Example

# Model
class Treasure < ActiveRecord::Base
  acts_as_location
end

# View
<% form_for @treasure do |f| %>
  <%= f.text_field :spot_marked_by %>
  <%= f.latitude_field :latitude %>
  <%= f.longitude_field :longitude %>
<% end %>

# Controller
# ...same as usual...

You'll get validation on every field (degrees, minutes, decimal-minutes, hemisphere) generated by the form helpers, though not the overall value any more (TBD).

Here's an example script/console session:

>> puts Treasure.find(:first).location
12°34.56′N, 012°34.56′W   # N.B. If this looks weird online, set your browser's text encoding to UTF-8.

>> puts Treasure.find(:first).location.latitude
12.576

>> puts Treasure.find(:first).location.longitude
-12.576

Someday / Maybe

  • Refactor the multiple string columns into a single string column (per lat. and per lng.), and use virtual attributes to map the single db field back and forth to multiple form fields. Add a float to 'cache' the lat/lng values. This will simplify the code significantly.
  • Add a validation for the overall latitude and longitude values (to catch for example 90°00.01′N).
  • Use method in the form helpers so user can give database columns different names (e.g. my_lat_degrees, etc). See the way Paperclip allows different attachment names.
  • DRY up form helper methods.
  • DRY up location.rb.

Intellectual Property

Copyright (c) 2010 Andy Stewart, AirBlade Software Ltd. Released under the MIT license

Something went wrong with that request. Please try again.