Skip to content

Commit

Permalink
making it work with mongoid 3 and array type for lat/lng
Browse files Browse the repository at this point in the history
  • Loading branch information
kristianmandrup committed Aug 4, 2012
1 parent 485b185 commit 646f416
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 18 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.3)
activemodel (~> 3.1)
moped (~> 1.1)
origin (~> 1.0)
tzinfo (~> 0.3.22)
moped (1.2.0)
multi_json (1.2.0)
origin (1.0.4)
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
8 changes: 8 additions & 0 deletions README.rdoc
Expand Up @@ -66,6 +66,14 @@ Create a migration and add the following fields to your table (here users):
add_column :users, :longitude, :float #you can change the name, see wiki
add_column :users, :gmaps, :boolean #not mandatory, see wiki

== Basic configuration: Non-relational DB

Mongoid example:

acts_as_gmappable :position => :location

field :location, :type => Array

== How to?
=== QuickStart!
In your controller:
Expand Down
Empty file added gemfiles/Mongoid-2.4.gemfile
Empty file.
Empty file added gemfiles/Mongoid-3.0.gemfile
Empty file.
1 change: 1 addition & 0 deletions gmaps4rails.gemspec
Expand Up @@ -17,6 +17,7 @@ Gem::Specification.new do |s|

s.add_development_dependency "rails", "~> 3.2.1"
s.add_development_dependency "sqlite3"
s.add_development_dependency "mongoid", "~> 3"
s.add_development_dependency 'jquery-rails'
s.add_development_dependency "rspec-rails"
s.add_development_dependency 'database_cleaner'
Expand Down
4 changes: 4 additions & 0 deletions lib/gmaps4rails/acts_as_gmappable.rb
Expand Up @@ -38,6 +38,10 @@ def acts_as_gmappable args = {}

:lat_column => args[:lat] || "latitude",
:lng_column => args[:lng] || "longitude",

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

:msg => args[:msg] || "Address invalid",
:validation => args[:validation].nil? ? true : args[:validation],
Expand Down
48 changes: 40 additions & 8 deletions lib/gmaps4rails/json_builder.rb
Expand Up @@ -73,18 +73,42 @@ def model_attributes
:title => :gmaps4rails_title,
:sidebar => :gmaps4rails_sidebar,
:marker_picture => :gmaps4rails_marker_picture,
:lat => @object.gmaps4rails_options[:lat_column],
:lng => @object.gmaps4rails_options[:lng_column]
}
}.merge(position_attributes)
end

def position_attributes
obj_option(:position) ? {:position => opt_value(:position)} : {:lat => opt_option(:lat_column), :lng => opt_option(:lng_column)}
end

def obj_option name
@object.gmaps4rails_options[:lng_column]
end

def opt_value name
@object.send(obj_option name)
end

def obj_value name
@object.send(name)
end

def obj_method? name
@object.respond_to?
end

def json_merge! hash
@json_hash.merge! hash
end

def handle_model_methods

This comment has been minimized.

Copy link
@apneadiving

apneadiving Aug 5, 2012

Why do you change the json created by the gem?

model_attributes.each do |json_name, method_name|
if @object.respond_to? method_name
if obj_method? method_name
if json_name == :marker_picture
@json_hash.merge!(@object.send(method_name)) unless @json_hash.has_key? "picture"
json_merge!(obj_value(method_name)) unless @json_hash.has_key? "picture"
elsif json_name == :position
json_merge!(:lat => obj_value(method_name)[0], :lng => obj_value(:position)[0])
else
@json_hash[json_name] = @object.send(method_name) unless @json_hash.has_key? json_name
@json_hash[json_name] = obj_value(method_name) unless @json_hash.has_key? json_name
end
end
end
Expand All @@ -99,7 +123,7 @@ def return_json
return @json_hash.to_json if @custom_json.nil?
case @custom_json
when Hash
@json_hash.merge! @custom_json
json_merge! @custom_json
return @json_hash.to_json
when String
output = @json_hash.to_json
Expand All @@ -108,7 +132,15 @@ def return_json
end

def compliant?
!(@object.send(@object.gmaps4rails_options[:lat_column]).blank? && @object.send(@object.gmaps4rails_options[:lng_column]).blank?)
obj_lat_lng? || obj_position?
end

def obj_lat_lng?
!obj_value(:lat_column).blank? && !obj_value(:lng_column).blank?
end

def obj_position?
!obj_value(:position).blank?
end

def handle_block(&block)
Expand Down
47 changes: 38 additions & 9 deletions lib/gmaps4rails/model_handler.rb
Expand Up @@ -4,9 +4,9 @@ class ModelHandler

attr_accessor :options, :object

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

def initialize(object, gmaps4rails_options)
@options = ::OpenStruct.new(gmaps4rails_options)
Expand All @@ -16,19 +16,48 @@ def initialize(object, gmaps4rails_options)
# saves coordinates according to the various options
def retrieve_coordinates
return if prevent_geocoding?
checked_coordinates do
object.send("#{lng_column}=", coordinates.first[:lng])
object.send("#{lat_column}=", coordinates.first[:lat])
# save normalized address if required
object.send("#{normalized_address}=", coordinates.first[:matched_address]) if normalized_address
checked_coordinates do
position? set_position : set_lat_lng
set_normalized_address if normalized_address
# Call the callback method to let the user do what he wants with the data
object.send(callback, coordinates.first[:full_data]) if callback
do_callback if callback
# update checker if required
object.send("#{checker}=", true) if check_geocoding?
set_checker if check_geocoding?
end
end

private

def do_callback
object.send(callback, coordinates.first[:full_data])
end

def set_checker
object.send("#{checker}=", true)
end

def set_normalized_address
# save normalized address if required
object.send("#{normalized_address}=", coordinates.first[:matched_address])
end

def set_position
object.send("#{position}=", coordinates)
end

def set_lat_lng
set_coordinate :lng
set_coordinate :lat
end

def set_coordinate name
column = send("#{name}_column")
object.send("#{column}=", coordinates.first[name.to_sym])
end

def position?
position
end

def checked_coordinates(&block)
yield if coordinates
Expand Down
12 changes: 12 additions & 0 deletions spec/dummy/app/models/place.rb
@@ -0,0 +1,12 @@
require 'mongoid'

class Place
include Mongoid::Document
include Gmaps4rails::ActsAsGmappable

acts_as_gmappable :address => :address, :position => :location

field :location, :type => Array
field :address, :type => String
field :gmaps, :type => Boolean
end
16 changes: 16 additions & 0 deletions spec/factories/place_factory.rb
@@ -0,0 +1,16 @@
FactoryGirl.define do
factory :place do

trait :paris do
address "Paris, France"
end

trait :invalid do
address "home"
end

address "Toulon, France"

factory :place_paris, :traits => [:paris]
end
end
43 changes: 43 additions & 0 deletions spec/models/place_spec.rb
@@ -0,0 +1,43 @@
require 'spec_helper'

include Geocoding

set_gmaps4rails_options!

require 'mongoid'

Mongoid.configure do |config|
Mongoid::VersionSetup.configure config
end

RSpec.configure do |config|
# config.mock_with(:mocha)

config.before(:each) do
Mongoid.purge!
# Mongoid.database.collections.each do |collection|
# unless collection.name =~ /^system\./
# collection.remove
# end
# end
end
end


describe Gmaps4rails::ActsAsGmappable do

let(:place) { Factory(:place) }
let(:invalid_place) { Factory.build(:invalid_place) }

before(:each) do
Geocoding.stub_geocoding
end

context "standard configuration, valid place" do
it "should save longitude and latitude to the customized array" do
set_gmaps4rails_options!(:lat_lng_array => 'location')
place.location.should_not be_nil
place.should have_same_position_as TOULON
end
end
end
64 changes: 63 additions & 1 deletion spec/support/matchers.rb
Expand Up @@ -27,9 +27,71 @@ def has_same_content_as?(actual, expected)
end
end

class PositionMatcher
attr_reader :object, :position

def initialize object
@object = object
@position = extract_position object
end

def same_pos? position_hash
same_lat?(position[0], position_hash) && same_lng?(position[1], position_hash)
end

protected

def extract_position object
position? obj_position :
if
end

def obj_create_position
[obj_coord(:lat), obj_coord(:lng)]
end

def position?
obj_option :position
end

def obj_position
obj_value :position
end

def obj_coord name
obj_value :"#{name}_column"
end

def obj_value name
object.send(obj_option name)
end

def obj_option name
object.gmaps4rails_options[name.to_sym]
end

def self.same_lat? lat, position_hash
lat == position_hash[:latitude]
end

def self.same_lng? lng, position_hash
lng == position_hash[:longitude]
end
end

def position_matcher object
PositionMatcher.new object
end

RSpec::Matchers.define :have_same_position_as do |position_hash|
match do |object|
position_matcher(object).same_pos? position_hash
end
end

RSpec::Matchers.define :have_same_position_as do |position_hash|
match do |object|
object.send(object.gmaps4rails_options[:lat_column]) == position_hash[:latitude] && object.send(object.gmaps4rails_options[:lng_column]) == position_hash[:longitude]
PositionMatcher.same_pos? object, position_hash
end
end

Expand Down

0 comments on commit 646f416

Please sign in to comment.