geokit-rails 2.3.2 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +29 -3
- data/CHANGELOG.md +5 -0
- data/README.markdown +7 -7
- data/gemfiles/rails3.gemfile +1 -0
- data/gemfiles/rails4.gemfile +1 -1
- data/gemfiles/rails5.gemfile +0 -1
- data/gemfiles/rails6.0.gemfile +8 -0
- data/gemfiles/rails6.1.gemfile +8 -0
- data/geokit-rails.gemspec +6 -5
- data/lib/geokit-rails/acts_as_mappable/class_methods.rb +297 -0
- data/lib/geokit-rails/acts_as_mappable/glue.rb +54 -0
- data/lib/geokit-rails/acts_as_mappable.rb +0 -347
- data/lib/geokit-rails/{core_extensions.rb → distance_collection.rb} +0 -0
- data/lib/geokit-rails/ip_geocode_lookup.rb +4 -7
- data/lib/geokit-rails/version.rb +1 -1
- data/lib/geokit-rails.rb +3 -1
- data/test/distance_collection_test.rb +42 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/stylesheets/application.css +1 -0
- data/test/dummy/app/channels/application_cable/channel.rb +4 -0
- data/test/dummy/app/channels/application_cable/connection.rb +4 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/controllers/location_aware_controller.rb +43 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/jobs/application_job.rb +7 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/models/application_record.rb +3 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +15 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +33 -0
- data/test/dummy/config/application.rb +22 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/cable.yml +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +68 -0
- data/test/dummy/config/environments/production.rb +87 -0
- data/test/dummy/config/environments/test.rb +60 -0
- data/test/dummy/config/initializers/content_security_policy.rb +25 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +8 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/permissions_policy.rb +11 -0
- data/test/dummy/config/locales/en.yml +33 -0
- data/test/dummy/config/puma.rb +43 -0
- data/test/dummy/config/routes.rb +6 -0
- data/test/dummy/config/storage.yml +34 -0
- data/test/dummy/config.ru +6 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/test/dummy/public/apple-touch-icon.png +0 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/storage/.keep +0 -0
- data/test/dummy/tmp/.keep +0 -0
- data/test/dummy/tmp/pids/.keep +0 -0
- data/test/dummy/tmp/storage/.keep +0 -0
- data/test/ip_geocode_lookup_test.rb +49 -0
- data/test/test_helper.rb +17 -0
- metadata +129 -27
- data/test/ip_geocode_lookup_test.disabled.rb +0 -82
@@ -6,56 +6,6 @@ module Geokit
|
|
6
6
|
|
7
7
|
class UnsupportedAdapter < StandardError ; end
|
8
8
|
|
9
|
-
# Add the +acts_as_mappable+ method into ActiveRecord subclasses
|
10
|
-
module Glue # :nodoc:
|
11
|
-
extend ActiveSupport::Concern
|
12
|
-
|
13
|
-
module ClassMethods # :nodoc:
|
14
|
-
OPTION_SYMBOLS = [ :distance_column_name, :default_units, :default_formula, :lat_column_name, :lng_column_name, :qualified_lat_column_name, :qualified_lng_column_name, :skip_loading ]
|
15
|
-
|
16
|
-
def acts_as_mappable(options = {})
|
17
|
-
metaclass = (class << self; self; end)
|
18
|
-
|
19
|
-
include Geokit::ActsAsMappable
|
20
|
-
|
21
|
-
cattr_accessor :through
|
22
|
-
self.through = options[:through]
|
23
|
-
|
24
|
-
if reflection = Geokit::ActsAsMappable.end_of_reflection_chain(self.through, self)
|
25
|
-
metaclass.instance_eval do
|
26
|
-
OPTION_SYMBOLS.each do |method_name|
|
27
|
-
define_method method_name do
|
28
|
-
reflection.klass.send(method_name)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
else
|
33
|
-
cattr_accessor *OPTION_SYMBOLS
|
34
|
-
|
35
|
-
self.distance_column_name = options[:distance_column_name] || 'distance'
|
36
|
-
self.default_units = options[:default_units] || Geokit::default_units
|
37
|
-
self.default_formula = options[:default_formula] || Geokit::default_formula
|
38
|
-
self.lat_column_name = options[:lat_column_name] || 'lat'
|
39
|
-
self.lng_column_name = options[:lng_column_name] || 'lng'
|
40
|
-
self.skip_loading = options[:skip_loading]
|
41
|
-
self.qualified_lat_column_name = "#{table_name}.#{lat_column_name}"
|
42
|
-
self.qualified_lng_column_name = "#{table_name}.#{lng_column_name}"
|
43
|
-
|
44
|
-
if options.include?(:auto_geocode) && options[:auto_geocode]
|
45
|
-
# if the form auto_geocode=>true is used, let the defaults take over by suppling an empty hash
|
46
|
-
options[:auto_geocode] = {} if options[:auto_geocode] == true
|
47
|
-
cattr_accessor :auto_geocode_field, :auto_geocode_error_message
|
48
|
-
self.auto_geocode_field = options[:auto_geocode][:field] || 'address'
|
49
|
-
self.auto_geocode_error_message = options[:auto_geocode][:error_message] || 'could not locate address'
|
50
|
-
|
51
|
-
# set the actual callback here
|
52
|
-
before_validation :auto_geocode_address, :on => :create
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end # Glue
|
58
|
-
|
59
9
|
#class Relation < ActiveRecord::Relation
|
60
10
|
# attr_accessor :distance_formula
|
61
11
|
|
@@ -90,299 +40,6 @@ module Geokit
|
|
90
40
|
include Geokit::Mappable
|
91
41
|
end
|
92
42
|
|
93
|
-
# Class methods included in models when +acts_as_mappable+ is called
|
94
|
-
module ClassMethods
|
95
|
-
|
96
|
-
# A proxy to an instance of a finder adapter, inferred from the connection's adapter.
|
97
|
-
def geokit_finder_adapter
|
98
|
-
@geokit_finder_adapter ||= begin
|
99
|
-
unless Adapters.const_defined?(connection.adapter_name.camelcase)
|
100
|
-
filename = connection.adapter_name.downcase
|
101
|
-
require File.join("geokit-rails", "adapters", filename)
|
102
|
-
end
|
103
|
-
klass = Adapters.const_get(connection.adapter_name.camelcase)
|
104
|
-
if klass.class == Module
|
105
|
-
# For some reason Mysql2 adapter was defined in Adapters.constants but was Module instead of a Class
|
106
|
-
filename = connection.adapter_name.downcase
|
107
|
-
require File.join("geokit-rails", "adapters", filename)
|
108
|
-
# Re-init the klass after require
|
109
|
-
klass = Adapters.const_get(connection.adapter_name.camelcase)
|
110
|
-
end
|
111
|
-
klass.load(self) unless klass.loaded || skip_loading
|
112
|
-
klass.new(self)
|
113
|
-
rescue LoadError
|
114
|
-
raise UnsupportedAdapter, "`#{connection.adapter_name.downcase}` is not a supported adapter."
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def within(distance, options = {})
|
119
|
-
options[:within] = distance
|
120
|
-
# Add bounding box to speed up SQL request.
|
121
|
-
bounds = formulate_bounds_from_distance(
|
122
|
-
options,
|
123
|
-
normalize_point_to_lat_lng(options[:origin]),
|
124
|
-
options[:units] || default_units)
|
125
|
-
with_latlng.where(bound_conditions(bounds)).
|
126
|
-
where(distance_conditions(options))
|
127
|
-
end
|
128
|
-
alias inside within
|
129
|
-
|
130
|
-
def beyond(distance, options = {})
|
131
|
-
options[:beyond] = distance
|
132
|
-
#geo_scope(options)
|
133
|
-
where(distance_conditions(options))
|
134
|
-
end
|
135
|
-
alias outside beyond
|
136
|
-
|
137
|
-
def in_range(range, options = {})
|
138
|
-
options[:range] = range
|
139
|
-
#geo_scope(options)
|
140
|
-
where(distance_conditions(options))
|
141
|
-
end
|
142
|
-
|
143
|
-
def in_bounds(bounds, options = {})
|
144
|
-
inclusive = options.delete(:inclusive) || false
|
145
|
-
options[:bounds] = bounds
|
146
|
-
#geo_scope(options)
|
147
|
-
#where(distance_conditions(options))
|
148
|
-
bounds = extract_bounds_from_options(options)
|
149
|
-
where(bound_conditions(bounds, inclusive))
|
150
|
-
end
|
151
|
-
|
152
|
-
def by_distance(options = {})
|
153
|
-
origin = extract_origin_from_options(options)
|
154
|
-
units = extract_units_from_options(options)
|
155
|
-
formula = extract_formula_from_options(options)
|
156
|
-
distance_column_name = distance_sql(origin, units, formula)
|
157
|
-
with_latlng.order(
|
158
|
-
Arel.sql(distance_column_name).send(options[:reverse] ? 'desc' : 'asc')
|
159
|
-
)
|
160
|
-
end
|
161
|
-
|
162
|
-
def with_latlng
|
163
|
-
where("#{qualified_lat_column_name} IS NOT NULL AND #{qualified_lng_column_name} IS NOT NULL")
|
164
|
-
end
|
165
|
-
|
166
|
-
def closest(options = {})
|
167
|
-
by_distance(options).limit(1)
|
168
|
-
end
|
169
|
-
alias nearest closest
|
170
|
-
|
171
|
-
def farthest(options = {})
|
172
|
-
by_distance({:reverse => true}.merge(options)).limit(1)
|
173
|
-
end
|
174
|
-
|
175
|
-
#def geo_scope(options = {})
|
176
|
-
# arel = self.is_a?(ActiveRecord::Relation) ? self : self.scoped
|
177
|
-
|
178
|
-
# origin = extract_origin_from_options(options)
|
179
|
-
# units = extract_units_from_options(options)
|
180
|
-
# formula = extract_formula_from_options(options)
|
181
|
-
# bounds = extract_bounds_from_options(options)
|
182
|
-
|
183
|
-
# if origin || bounds
|
184
|
-
# bounds = formulate_bounds_from_distance(options, origin, units) unless bounds
|
185
|
-
|
186
|
-
# if origin
|
187
|
-
# arel.distance_formula = distance_sql(origin, units, formula)
|
188
|
-
#
|
189
|
-
# if arel.select_values.blank?
|
190
|
-
# star_select = Arel::Nodes::SqlLiteral.new(arel.quoted_table_name + '.*')
|
191
|
-
# arel = arel.select(star_select)
|
192
|
-
# end
|
193
|
-
# end
|
194
|
-
|
195
|
-
# if bounds
|
196
|
-
# bound_conditions = bound_conditions(bounds)
|
197
|
-
# arel = arel.where(bound_conditions) if bound_conditions
|
198
|
-
# end
|
199
|
-
|
200
|
-
# distance_conditions = distance_conditions(options)
|
201
|
-
# arel = arel.where(distance_conditions) if distance_conditions
|
202
|
-
|
203
|
-
# if self.through
|
204
|
-
# arel = arel.includes(self.through)
|
205
|
-
# end
|
206
|
-
# end
|
207
|
-
|
208
|
-
# arel
|
209
|
-
#end
|
210
|
-
|
211
|
-
# Returns the distance calculation to be used as a display column or a condition. This
|
212
|
-
# is provide for anyone wanting access to the raw SQL.
|
213
|
-
def distance_sql(origin, units=default_units, formula=default_formula)
|
214
|
-
case formula
|
215
|
-
when :sphere
|
216
|
-
sql = sphere_distance_sql(origin, units)
|
217
|
-
when :flat
|
218
|
-
sql = flat_distance_sql(origin, units)
|
219
|
-
end
|
220
|
-
sql
|
221
|
-
end
|
222
|
-
|
223
|
-
private
|
224
|
-
|
225
|
-
# Override ActiveRecord::Base.relation to return an instance of Geokit::ActsAsMappable::Relation.
|
226
|
-
# TODO: Do we need to override JoinDependency#relation too?
|
227
|
-
#def relation
|
228
|
-
# # NOTE: This cannot be @relation as ActiveRecord already uses this to
|
229
|
-
# # cache *its* Relation object
|
230
|
-
# @_geokit_relation ||= Relation.new(self, arel_table)
|
231
|
-
# finder_needs_type_condition? ? @_geokit_relation.where(type_condition) : @_geokit_relation
|
232
|
-
#end
|
233
|
-
|
234
|
-
# If it's a :within query, add a bounding box to improve performance.
|
235
|
-
# This only gets called if a :bounds argument is not otherwise supplied.
|
236
|
-
def formulate_bounds_from_distance(options, origin, units)
|
237
|
-
distance = options[:within] if options.has_key?(:within) && options[:within].is_a?(Numeric)
|
238
|
-
distance = options[:range].last-(options[:range].exclude_end?? 1 : 0) if options.has_key?(:range)
|
239
|
-
if distance
|
240
|
-
Geokit::Bounds.from_point_and_radius(origin,distance,:units=>units)
|
241
|
-
else
|
242
|
-
nil
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
def distance_conditions(options)
|
247
|
-
origin = extract_origin_from_options(options)
|
248
|
-
units = extract_units_from_options(options)
|
249
|
-
formula = extract_formula_from_options(options)
|
250
|
-
distance_column_name = distance_sql(origin, units, formula)
|
251
|
-
|
252
|
-
if options.has_key?(:within)
|
253
|
-
Arel.sql(distance_column_name).lteq(options[:within])
|
254
|
-
elsif options.has_key?(:beyond)
|
255
|
-
Arel.sql(distance_column_name).gt(options[:beyond])
|
256
|
-
elsif options.has_key?(:range)
|
257
|
-
min_condition = Arel.sql(distance_column_name).gteq(options[:range].begin)
|
258
|
-
max_condition = if options[:range].exclude_end?
|
259
|
-
Arel.sql(distance_column_name).lt(options[:range].end)
|
260
|
-
else
|
261
|
-
Arel.sql(distance_column_name).lteq(options[:range].end)
|
262
|
-
end
|
263
|
-
min_condition.and(max_condition)
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
def bound_conditions(bounds, inclusive = false)
|
268
|
-
return nil unless bounds
|
269
|
-
if inclusive
|
270
|
-
lt_operator = :lteq
|
271
|
-
gt_operator = :gteq
|
272
|
-
else
|
273
|
-
lt_operator = :lt
|
274
|
-
gt_operator = :gt
|
275
|
-
end
|
276
|
-
sw,ne = bounds.sw, bounds.ne
|
277
|
-
lat, lng = Arel.sql(qualified_lat_column_name), Arel.sql(qualified_lng_column_name)
|
278
|
-
lat.send(gt_operator, sw.lat).and(lat.send(lt_operator, ne.lat)).and(
|
279
|
-
if bounds.crosses_meridian?
|
280
|
-
lng.send(lt_operator, ne.lng).or(lng.send(gt_operator, sw.lng))
|
281
|
-
else
|
282
|
-
lng.send(gt_operator, sw.lng).and(lng.send(lt_operator, ne.lng))
|
283
|
-
end
|
284
|
-
)
|
285
|
-
end
|
286
|
-
|
287
|
-
# Extracts the origin instance out of the options if it exists and returns
|
288
|
-
# it. If there is no origin, looks for latitude and longitude values to
|
289
|
-
# create an origin. The side-effect of the method is to remove these
|
290
|
-
# option keys from the hash.
|
291
|
-
def extract_origin_from_options(options)
|
292
|
-
origin = options.delete(:origin)
|
293
|
-
res = normalize_point_to_lat_lng(origin) if origin
|
294
|
-
res
|
295
|
-
end
|
296
|
-
|
297
|
-
# Extract the units out of the options if it exists and returns it. If
|
298
|
-
# there is no :units key, it uses the default. The side effect of the
|
299
|
-
# method is to remove the :units key from the options hash.
|
300
|
-
def extract_units_from_options(options)
|
301
|
-
units = options[:units] || default_units
|
302
|
-
options.delete(:units)
|
303
|
-
units
|
304
|
-
end
|
305
|
-
|
306
|
-
# Extract the formula out of the options if it exists and returns it. If
|
307
|
-
# there is no :formula key, it uses the default. The side effect of the
|
308
|
-
# method is to remove the :formula key from the options hash.
|
309
|
-
def extract_formula_from_options(options)
|
310
|
-
formula = options[:formula] || default_formula
|
311
|
-
options.delete(:formula)
|
312
|
-
formula
|
313
|
-
end
|
314
|
-
|
315
|
-
def extract_bounds_from_options(options)
|
316
|
-
bounds = options.delete(:bounds)
|
317
|
-
bounds = Geokit::Bounds.normalize(bounds) if bounds
|
318
|
-
end
|
319
|
-
|
320
|
-
# Geocode IP address.
|
321
|
-
def geocode_ip_address(origin)
|
322
|
-
geo_location = Geokit::Geocoders::MultiGeocoder.geocode(origin)
|
323
|
-
return geo_location if geo_location.success
|
324
|
-
raise Geokit::Geocoders::GeocodeError
|
325
|
-
end
|
326
|
-
|
327
|
-
# Given a point in a variety of (an address to geocode,
|
328
|
-
# an array of [lat,lng], or an object with appropriate lat/lng methods, an IP addres)
|
329
|
-
# this method will normalize it into a Geokit::LatLng instance. The only thing this
|
330
|
-
# method adds on top of LatLng#normalize is handling of IP addresses
|
331
|
-
def normalize_point_to_lat_lng(point)
|
332
|
-
res = geocode_ip_address(point) if point.is_a?(String) && /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(point)
|
333
|
-
res = Geokit::LatLng.normalize(point) unless res
|
334
|
-
res
|
335
|
-
end
|
336
|
-
|
337
|
-
# Looks for the distance column and replaces it with the distance sql. If an origin was not
|
338
|
-
# passed in and the distance column exists, we leave it to be flagged as bad SQL by the database.
|
339
|
-
# Conditions are either a string or an array. In the case of an array, the first entry contains
|
340
|
-
# the condition.
|
341
|
-
def substitute_distance_in_where_values(arel, origin, units=default_units, formula=default_formula)
|
342
|
-
pattern = Regexp.new("\\b#{distance_column_name}\\b")
|
343
|
-
value = distance_sql(origin, units, formula)
|
344
|
-
arel.where_values.map! do |where_value|
|
345
|
-
if where_value.is_a?(String)
|
346
|
-
where_value.gsub(pattern, value)
|
347
|
-
else
|
348
|
-
where_value
|
349
|
-
end
|
350
|
-
end
|
351
|
-
arel
|
352
|
-
end
|
353
|
-
|
354
|
-
# Returns the distance SQL using the spherical world formula (Haversine). The SQL is tuned
|
355
|
-
# to the database in use.
|
356
|
-
def sphere_distance_sql(origin, units)
|
357
|
-
# "origin" can be a Geokit::LatLng (with :lat and :lng methods), e.g.
|
358
|
-
# when using geo_scope or it can be an ActsAsMappable with customized
|
359
|
-
# latitude and longitude methods, e.g. when using distance_sql.
|
360
|
-
lat = deg2rad(get_lat(origin))
|
361
|
-
lng = deg2rad(get_lng(origin))
|
362
|
-
multiplier = units_sphere_multiplier(units)
|
363
|
-
geokit_finder_adapter.sphere_distance_sql(lat, lng, multiplier) if geokit_finder_adapter
|
364
|
-
end
|
365
|
-
|
366
|
-
# Returns the distance SQL using the flat-world formula (Phythagorean Theory). The SQL is tuned
|
367
|
-
# to the database in use.
|
368
|
-
def flat_distance_sql(origin, units)
|
369
|
-
lat_degree_units = units_per_latitude_degree(units)
|
370
|
-
lng_degree_units = units_per_longitude_degree(get_lat(origin), units)
|
371
|
-
geokit_finder_adapter.flat_distance_sql(origin, lat_degree_units, lng_degree_units)
|
372
|
-
end
|
373
|
-
|
374
|
-
def get_lat(origin)
|
375
|
-
origin.respond_to?(:lat) ? origin.lat \
|
376
|
-
: origin.send(:"#{lat_column_name}")
|
377
|
-
end
|
378
|
-
|
379
|
-
def get_lng(origin)
|
380
|
-
origin.respond_to?(:lng) ? origin.lng \
|
381
|
-
: origin.send(:"#{lng_column_name}")
|
382
|
-
end
|
383
|
-
|
384
|
-
end # ClassMethods
|
385
|
-
|
386
43
|
# this is the callback for auto_geocoding
|
387
44
|
def auto_geocode_address
|
388
45
|
address=self.send(auto_geocode_field).to_s
|
@@ -419,7 +76,3 @@ module Geokit
|
|
419
76
|
|
420
77
|
end # ActsAsMappable
|
421
78
|
end # Geokit
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
# ActiveRecord::Base.extend Geokit::ActsAsMappable
|
File without changes
|
@@ -12,11 +12,7 @@ module Geokit
|
|
12
12
|
# Class method to mix into active record.
|
13
13
|
module ClassMethods # :nodoc:
|
14
14
|
def geocode_ip_address(filter_options = {})
|
15
|
-
|
16
|
-
before_action :store_ip_location, filter_options
|
17
|
-
else
|
18
|
-
before_filter :store_ip_location, filter_options
|
19
|
-
end
|
15
|
+
before_action :store_ip_location, filter_options
|
20
16
|
end
|
21
17
|
end
|
22
18
|
|
@@ -28,13 +24,14 @@ module Geokit
|
|
28
24
|
# get the value.
|
29
25
|
def store_ip_location
|
30
26
|
session[:geo_location] ||= retrieve_location_from_cookie_or_service
|
31
|
-
cookies[:geo_location] = { :value => session[:geo_location].
|
27
|
+
cookies[:geo_location] = { :value => session[:geo_location].to_json, :expires => 30.days.from_now } if session[:geo_location]
|
32
28
|
end
|
33
29
|
|
34
30
|
# Uses the stored location value from the cookie if it exists. If
|
35
31
|
# no cookie exists, calls out to the web service to get the location.
|
36
32
|
def retrieve_location_from_cookie_or_service
|
37
|
-
return GeoLoc.new(YAML.load(cookies[:geo_location])) if cookies[:geo_location]
|
33
|
+
# return GeoLoc.new(YAML.load(cookies[:geo_location])) if cookies[:geo_location]
|
34
|
+
return GeoLoc.new(JSON.parse(cookies[:geo_location])) if cookies[:geo_location]
|
38
35
|
location = Geocoders::MultiGeocoder.geocode(get_ip_address)
|
39
36
|
return location.success ? location : nil
|
40
37
|
end
|
data/lib/geokit-rails/version.rb
CHANGED
data/lib/geokit-rails.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'geokit'
|
2
2
|
|
3
3
|
require 'geokit-rails/railtie'
|
4
|
-
require 'geokit-rails/
|
4
|
+
require 'geokit-rails/distance_collection'
|
5
5
|
|
6
6
|
require 'geokit-rails/adapters/abstract'
|
7
|
+
require 'geokit-rails/acts_as_mappable/glue'
|
8
|
+
require 'geokit-rails/acts_as_mappable/class_methods'
|
7
9
|
require 'geokit-rails/acts_as_mappable'
|
8
10
|
require 'geokit-rails/geocoder_control'
|
9
11
|
require 'geokit-rails/ip_geocode_lookup'
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
Geokit::Geocoders::provider_order = [:google, :us]
|
4
|
+
|
5
|
+
class DistanceCollectionTest < GeokitTestCase
|
6
|
+
|
7
|
+
LOCATION_A_IP = "217.10.83.5"
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@location_a = Geokit::GeoLoc.new
|
11
|
+
@location_a.lat = 32.918593
|
12
|
+
@location_a.lng = -96.958444
|
13
|
+
@location_a.city = "Irving"
|
14
|
+
@location_a.state = "TX"
|
15
|
+
@location_a.country_code = "US"
|
16
|
+
@location_a.success = true
|
17
|
+
|
18
|
+
@sw = Geokit::LatLng.new(32.91663,-96.982841)
|
19
|
+
@ne = Geokit::LatLng.new(32.96302,-96.919495)
|
20
|
+
@bounds_center=Geokit::LatLng.new((@sw.lat+@ne.lat)/2,(@sw.lng+@ne.lng)/2)
|
21
|
+
|
22
|
+
@starbucks = companies(:starbucks)
|
23
|
+
@loc_a = locations(:a)
|
24
|
+
@custom_loc_a = custom_locations(:a)
|
25
|
+
@loc_e = locations(:e)
|
26
|
+
@custom_loc_e = custom_locations(:e)
|
27
|
+
|
28
|
+
@barnes_and_noble = mock_organizations(:barnes_and_noble)
|
29
|
+
@address = mock_addresses(:address_barnes_and_noble)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_distance_collection
|
33
|
+
# Improve this test later on.
|
34
|
+
locations = Location.with_latlng.all
|
35
|
+
unsorted = [locations(:a), locations(:b), locations(:c), locations(:d), locations(:e), locations(:f)]
|
36
|
+
sorted_manually = locations.sort_by{|l| l.distance_to(locations(:a))}
|
37
|
+
sorted_automatically = DistanceCollection.new(unsorted)
|
38
|
+
sorted_automatically.set_distance_from(locations(:a))
|
39
|
+
assert_equal sorted_manually, sorted_automatically.sort_by(&:distance)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/test/dummy/Rakefile
ADDED
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
/* Application styles */
|
File without changes
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class LocationAwareController < ApplicationController #:nodoc: all
|
2
|
+
before_action :set_ip, only: [:index,:cookietest,:sessiontest]
|
3
|
+
before_action :set_ip_bad, only: [:failtest]
|
4
|
+
before_action :setup, only: [:cookietest,:sessiontest]
|
5
|
+
geocode_ip_address
|
6
|
+
|
7
|
+
def index
|
8
|
+
render plain: ''
|
9
|
+
end
|
10
|
+
|
11
|
+
def cookietest
|
12
|
+
cookies[:geo_location] = @success.to_json
|
13
|
+
render plain: ''
|
14
|
+
end
|
15
|
+
|
16
|
+
def sessiontest
|
17
|
+
session[:geo_location] = @success.to_json
|
18
|
+
render plain: ''
|
19
|
+
end
|
20
|
+
|
21
|
+
def failtest
|
22
|
+
render plain: ''
|
23
|
+
end
|
24
|
+
|
25
|
+
def rescue_action(e) raise e end;
|
26
|
+
private
|
27
|
+
def set_ip
|
28
|
+
request.remote_ip = "good ip"
|
29
|
+
end
|
30
|
+
def set_ip_bad
|
31
|
+
request.remote_ip = "bad ip"
|
32
|
+
end
|
33
|
+
def setup
|
34
|
+
@success = Geokit::GeoLoc.new
|
35
|
+
@success.provider = "hostip"
|
36
|
+
@success.lat = 41.7696
|
37
|
+
@success.lng = -88.4588
|
38
|
+
@success.city = "Sugar Grove"
|
39
|
+
@success.state = "IL"
|
40
|
+
@success.country_code = "US"
|
41
|
+
@success.success = true
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
class ApplicationJob < ActiveJob::Base
|
2
|
+
# Automatically retry jobs that encountered a deadlock
|
3
|
+
# retry_on ActiveRecord::Deadlocked
|
4
|
+
|
5
|
+
# Most jobs are safe to ignore if the underlying records are no longer available
|
6
|
+
# discard_on ActiveJob::DeserializationError
|
7
|
+
end
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Dummy</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<%= csrf_meta_tags %>
|
7
|
+
<%= csp_meta_tag %>
|
8
|
+
|
9
|
+
<%= stylesheet_link_tag "application" %>
|
10
|
+
</head>
|
11
|
+
|
12
|
+
<body>
|
13
|
+
<%= yield %>
|
14
|
+
</body>
|
15
|
+
</html>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= yield %>
|
data/test/dummy/bin/rake
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
# path to your application root.
|
5
|
+
APP_ROOT = File.expand_path("..", __dir__)
|
6
|
+
|
7
|
+
def system!(*args)
|
8
|
+
system(*args) || abort("\n== Command #{args} failed ==")
|
9
|
+
end
|
10
|
+
|
11
|
+
FileUtils.chdir APP_ROOT do
|
12
|
+
# This script is a way to set up or update your development environment automatically.
|
13
|
+
# This script is idempotent, so that you can run it at any time and get an expectable outcome.
|
14
|
+
# Add necessary setup steps to this file.
|
15
|
+
|
16
|
+
puts "== Installing dependencies =="
|
17
|
+
system! "gem install bundler --conservative"
|
18
|
+
system("bundle check") || system!("bundle install")
|
19
|
+
|
20
|
+
# puts "\n== Copying sample files =="
|
21
|
+
# unless File.exist?("config/database.yml")
|
22
|
+
# FileUtils.cp "config/database.yml.sample", "config/database.yml"
|
23
|
+
# end
|
24
|
+
|
25
|
+
puts "\n== Preparing database =="
|
26
|
+
system! "bin/rails db:prepare"
|
27
|
+
|
28
|
+
puts "\n== Removing old logs and tempfiles =="
|
29
|
+
system! "bin/rails log:clear tmp:clear"
|
30
|
+
|
31
|
+
puts "\n== Restarting application server =="
|
32
|
+
system! "bin/rails restart"
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative "boot"
|
2
|
+
|
3
|
+
require "rails/all"
|
4
|
+
|
5
|
+
# Require the gems listed in Gemfile, including any gems
|
6
|
+
# you've limited to :test, :development, or :production.
|
7
|
+
Bundler.require(*Rails.groups)
|
8
|
+
require "geokit-rails"
|
9
|
+
|
10
|
+
module Dummy
|
11
|
+
class Application < Rails::Application
|
12
|
+
config.load_defaults Rails::VERSION::STRING.to_f
|
13
|
+
|
14
|
+
# Configuration for the application, engines, and railties goes here.
|
15
|
+
#
|
16
|
+
# These settings can be overridden in specific environments using the files
|
17
|
+
# in config/environments, which are processed later.
|
18
|
+
#
|
19
|
+
# config.time_zone = "Central Time (US & Canada)"
|
20
|
+
# config.eager_load_paths << Rails.root.join("extras")
|
21
|
+
end
|
22
|
+
end
|