Skip to content

Commit

Permalink
enable integration with geocoder for mongo using reverse internal arr…
Browse files Browse the repository at this point in the history
…ay format [lng,lat]
  • Loading branch information
kristianmandrup committed Sep 7, 2012
1 parent 2df768b commit dd9c8de
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 9 deletions.
8 changes: 8 additions & 0 deletions Gemfile.lock
Expand Up @@ -91,7 +91,14 @@ GEM
treetop (~> 1.4.8)
method_source (0.7.1)
mime-types (1.18)
mongoid (3.0.5)
activemodel (~> 3.1)
moped (~> 1.1)
origin (~> 1.0)
tzinfo (~> 0.3.22)
moped (1.2.1)
multi_json (1.2.0)
origin (1.0.7)
polyglot (0.3.3)
pry (0.9.8.4)
coderay (~> 1.0.5)
Expand Down Expand Up @@ -172,6 +179,7 @@ DEPENDENCIES
guard-spork
jasmine
jquery-rails
mongoid (~> 3)
pry
rails (~> 3.2.1)
rspec-rails
Expand Down
6 changes: 6 additions & 0 deletions README.rdoc
Expand Up @@ -74,6 +74,12 @@ Mongoid example:

field :location, :type => Array

By default this uses the [lng, lat] position format. You can reverse this format, by specifying `:pos_order => [:lng, :lat]`

From [geocoder](https://github.com/alexreisner/geocoder) - Latitude/Longitude Order.

_"Coordinates are generally printed and spoken as latitude, then longitude ([lat,lon]).Geocoder respects this convention and always expects method arguments to be given in [lat,lon] order. However, MongoDB requires that coordinates be stored in [lon,lat] order as per the GeoJSON spec (geojson.org/geojson-spec.html#positions), so internally they are stored “backwards.” However, this does not affect order of arguments to methods when using Mongoid or MongoMapper."_

== How to?
=== QuickStart!
In your controller:
Expand Down
3 changes: 2 additions & 1 deletion lib/gmaps4rails/acts_as_gmappable.rb
Expand Up @@ -33,7 +33,8 @@ def acts_as_gmappable args = {}

# purposefully no default.
# Leaving out the :position arg means we are using the default lat/lng to store coordinates
:position => args[:position],
:position => args[:position],
:pos_order => args[:pos_order] || [:lat, :lng],

:msg => args[:msg] || "Address invalid",
:validation => args[:validation].nil? ? true : args[:validation],
Expand Down
14 changes: 11 additions & 3 deletions lib/gmaps4rails/json_builder.rb
Expand Up @@ -26,7 +26,7 @@ module Gmaps4rails
#
class JsonBuilder

delegate :position, :lat_column, :lng_column, :to => :@options
delegate :position, :lat_column, :lng_column, :pos_order, :to => :@options

def initialize(object)
@object, @json_hash, @custom_json = object, Hash.new, nil
Expand Down Expand Up @@ -127,12 +127,20 @@ def position_from_array?
position #if gmaps4rails_options[:position] is filled, means user is indicating an array
end

def lat_index
pos_order.first == :lat ? 0 : 1
end

def lng_index
pos_order.first == :lng ? 0 : 1
end

def lat
position_from_array? ? @object.send("#{position}")[0] : @object.send("#{lat_column}")
position_from_array? ? @object.send("#{position}")[lat_index] : @object.send("#{lat_column}")
end

def lng
position_from_array? ? @object.send("#{position}")[1] : @object.send("#{lng_column}")
position_from_array? ? @object.send("#{position}")[lng_index] : @object.send("#{lng_column}")
end

end
Expand Down
8 changes: 6 additions & 2 deletions lib/gmaps4rails/model_handler.rb
Expand Up @@ -4,7 +4,7 @@ class ModelHandler

attr_accessor :options, :object

delegate :process_geocoding, :check_process, :checker, :lat_column, :lng_column, :position, :msg, :validation,
delegate :process_geocoding, :check_process, :checker, :lat_column, :lng_column, :position, :pos_order, :msg, :validation,
:language, :protocol, :address, :callback, :normalized_address,
:to => :options

Expand All @@ -31,7 +31,11 @@ def retrieve_coordinates

# sets array for non relationnal db
def set_position
object.send("#{position}=", [lat, lng])
if pos_order.first == :lat
object.send("#{position}=", [lat, lng])
else
object.send("#{position}=", [lng, lat])
end
end

#sets regular columns
Expand Down
18 changes: 18 additions & 0 deletions spec/dummy/app/models/geo_place.rb
@@ -0,0 +1,18 @@
if RUBY_VERSION == "1.9.3"

require 'mongoid'

class GeoPlace
include Mongoid::Document
include Gmaps4rails::ActsAsGmappable

# Array position format in the form: [lng, lat]
# This format is f.ex used by *geocoder* gem
acts_as_gmappable :address => :address, :position => :pos, :pos_order => [:lng, :lat]

field :pos, :type => Array
field :address, :type => String
field :gmaps, :type => Boolean
end

end
16 changes: 16 additions & 0 deletions spec/factories/geo_place_factory.rb
@@ -0,0 +1,16 @@
FactoryGirl.define do
factory :geo_place do

trait :paris do
address "Paris, France"
end

trait :invalid do
address "home"
end

address "Toulon, France"

factory :geo_place_paris, :traits => [:paris]
end
end
37 changes: 37 additions & 0 deletions spec/models/geo_place_spec.rb
@@ -0,0 +1,37 @@
if RUBY_VERSION == "1.9.3"

require 'spec_helper'

include Geocoding

set_gmaps4rails_options!

# Mongoid 3.x only
require 'mongoid'
require 'moped'

Mongoid.configure do |config|
config.connect_to('mongoid_geo_test')
end

describe Gmaps4rails::ActsAsGmappable do

# Tests Array position format in the form: [lng, lat]
# F.ex required for integration with *geocoder* gem
let(:geo_place) { Factory(:geo_place) }
let(:invalid_geo_place) { Factory.build(:invalid_geo_place) }

before(:each) do
Geocoding.stub_geocoding
end

context "standard configuration, valid place" do
it "should save longitude and latitude to the customized position array" do
set_gmaps4rails_options!(:position => 'location', :pos_order => [:lng, :lat])
geo_place.pos.should_not be_nil
geo_place.should have_same_position_as TOULON
end
end
end

end
14 changes: 11 additions & 3 deletions spec/support/matchers.rb
Expand Up @@ -30,7 +30,7 @@ def has_same_content_as?(actual, expected)

class PositionMatcher
attr_reader :object, :position_hash
delegate :position, :lat_column, :lng_column, :to => :@options
delegate :position, :lat_column, :lng_column, :pos_order, :to => :@options

def initialize object, position_hash
@object, @position_hash = object, position_hash
Expand All @@ -43,12 +43,20 @@ def same_pos?

protected

def lat_index
pos_order.first == :lat ? 0 : 1
end

def lng_index
pos_order.first == :lng ? 0 : 1
end

def lat
position ? object.send("#{position}")[0] : object.send("#{lat_column}")
position ? object.send("#{position}")[lat_index] : object.send("#{lat_column}")
end

def lng
position ? object.send("#{position}")[1] : object.send("#{lng_column}")
position ? object.send("#{position}")[lng_index] : object.send("#{lng_column}")
end

end
Expand Down

0 comments on commit dd9c8de

Please sign in to comment.