geokit-rails 2.3.1 → 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.
Files changed (74) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +29 -3
  3. data/CHANGELOG.md +9 -0
  4. data/README.markdown +13 -7
  5. data/gemfiles/rails3.gemfile +1 -0
  6. data/gemfiles/rails4.gemfile +1 -1
  7. data/gemfiles/rails5.gemfile +0 -1
  8. data/gemfiles/rails6.0.gemfile +8 -0
  9. data/gemfiles/rails6.1.gemfile +8 -0
  10. data/geokit-rails.gemspec +6 -5
  11. data/lib/geokit-rails/acts_as_mappable/class_methods.rb +297 -0
  12. data/lib/geokit-rails/acts_as_mappable/glue.rb +54 -0
  13. data/lib/geokit-rails/acts_as_mappable.rb +0 -329
  14. data/lib/geokit-rails/adapters/sqlite.rb +2 -2
  15. data/lib/geokit-rails/{core_extensions.rb → distance_collection.rb} +0 -0
  16. data/lib/geokit-rails/ip_geocode_lookup.rb +4 -7
  17. data/lib/geokit-rails/version.rb +1 -1
  18. data/lib/geokit-rails.rb +3 -1
  19. data/test/acts_as_mappable_test.rb +16 -0
  20. data/test/distance_collection_test.rb +42 -0
  21. data/test/dummy/Rakefile +6 -0
  22. data/test/dummy/app/assets/images/.keep +0 -0
  23. data/test/dummy/app/assets/stylesheets/application.css +1 -0
  24. data/test/dummy/app/channels/application_cable/channel.rb +4 -0
  25. data/test/dummy/app/channels/application_cable/connection.rb +4 -0
  26. data/test/dummy/app/controllers/application_controller.rb +3 -0
  27. data/test/dummy/app/controllers/concerns/.keep +0 -0
  28. data/test/dummy/app/controllers/location_aware_controller.rb +43 -0
  29. data/test/dummy/app/helpers/application_helper.rb +2 -0
  30. data/test/dummy/app/jobs/application_job.rb +7 -0
  31. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  32. data/test/dummy/app/models/application_record.rb +3 -0
  33. data/test/dummy/app/models/concerns/.keep +0 -0
  34. data/test/dummy/app/views/layouts/application.html.erb +15 -0
  35. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  36. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  37. data/test/dummy/bin/rails +4 -0
  38. data/test/dummy/bin/rake +4 -0
  39. data/test/dummy/bin/setup +33 -0
  40. data/test/dummy/config/application.rb +22 -0
  41. data/test/dummy/config/boot.rb +5 -0
  42. data/test/dummy/config/cable.yml +10 -0
  43. data/test/dummy/config/database.yml +25 -0
  44. data/test/dummy/config/environment.rb +5 -0
  45. data/test/dummy/config/environments/development.rb +68 -0
  46. data/test/dummy/config/environments/production.rb +87 -0
  47. data/test/dummy/config/environments/test.rb +60 -0
  48. data/test/dummy/config/initializers/content_security_policy.rb +25 -0
  49. data/test/dummy/config/initializers/filter_parameter_logging.rb +8 -0
  50. data/test/dummy/config/initializers/inflections.rb +16 -0
  51. data/test/dummy/config/initializers/permissions_policy.rb +11 -0
  52. data/test/dummy/config/locales/en.yml +33 -0
  53. data/test/dummy/config/puma.rb +43 -0
  54. data/test/dummy/config/routes.rb +6 -0
  55. data/test/dummy/config/storage.yml +34 -0
  56. data/test/dummy/config.ru +6 -0
  57. data/test/dummy/lib/assets/.keep +0 -0
  58. data/test/dummy/log/.keep +0 -0
  59. data/test/dummy/public/404.html +67 -0
  60. data/test/dummy/public/422.html +67 -0
  61. data/test/dummy/public/500.html +66 -0
  62. data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
  63. data/test/dummy/public/apple-touch-icon.png +0 -0
  64. data/test/dummy/public/favicon.ico +0 -0
  65. data/test/dummy/storage/.keep +0 -0
  66. data/test/dummy/tmp/.keep +0 -0
  67. data/test/dummy/tmp/pids/.keep +0 -0
  68. data/test/dummy/tmp/storage/.keep +0 -0
  69. data/test/fixtures/companies.yml +3 -1
  70. data/test/ip_geocode_lookup_test.rb +49 -0
  71. data/test/schema.rb +1 -0
  72. data/test/test_helper.rb +17 -0
  73. metadata +128 -27
  74. 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,281 +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
- options[:bounds] = bounds
145
- #geo_scope(options)
146
- #where(distance_conditions(options))
147
- bounds = extract_bounds_from_options(options)
148
- where(bound_conditions(bounds))
149
- end
150
-
151
- def by_distance(options = {})
152
- origin = extract_origin_from_options(options)
153
- units = extract_units_from_options(options)
154
- formula = extract_formula_from_options(options)
155
- distance_column_name = distance_sql(origin, units, formula)
156
- with_latlng.order(Arel.sql(
157
- "#{distance_column_name} #{options[:reverse] ? 'DESC' : 'ASC'}"
158
- ))
159
- end
160
-
161
- def with_latlng
162
- where("#{qualified_lat_column_name} IS NOT NULL AND #{qualified_lng_column_name} IS NOT NULL")
163
- end
164
-
165
- def closest(options = {})
166
- by_distance(options).limit(1)
167
- end
168
- alias nearest closest
169
-
170
- def farthest(options = {})
171
- by_distance({:reverse => true}.merge(options)).limit(1)
172
- end
173
-
174
- #def geo_scope(options = {})
175
- # arel = self.is_a?(ActiveRecord::Relation) ? self : self.scoped
176
-
177
- # origin = extract_origin_from_options(options)
178
- # units = extract_units_from_options(options)
179
- # formula = extract_formula_from_options(options)
180
- # bounds = extract_bounds_from_options(options)
181
-
182
- # if origin || bounds
183
- # bounds = formulate_bounds_from_distance(options, origin, units) unless bounds
184
-
185
- # if origin
186
- # arel.distance_formula = distance_sql(origin, units, formula)
187
- #
188
- # if arel.select_values.blank?
189
- # star_select = Arel::Nodes::SqlLiteral.new(arel.quoted_table_name + '.*')
190
- # arel = arel.select(star_select)
191
- # end
192
- # end
193
-
194
- # if bounds
195
- # bound_conditions = bound_conditions(bounds)
196
- # arel = arel.where(bound_conditions) if bound_conditions
197
- # end
198
-
199
- # distance_conditions = distance_conditions(options)
200
- # arel = arel.where(distance_conditions) if distance_conditions
201
-
202
- # if self.through
203
- # arel = arel.includes(self.through)
204
- # end
205
- # end
206
-
207
- # arel
208
- #end
209
-
210
- # Returns the distance calculation to be used as a display column or a condition. This
211
- # is provide for anyone wanting access to the raw SQL.
212
- def distance_sql(origin, units=default_units, formula=default_formula)
213
- case formula
214
- when :sphere
215
- sql = sphere_distance_sql(origin, units)
216
- when :flat
217
- sql = flat_distance_sql(origin, units)
218
- end
219
- sql
220
- end
221
-
222
- private
223
-
224
- # Override ActiveRecord::Base.relation to return an instance of Geokit::ActsAsMappable::Relation.
225
- # TODO: Do we need to override JoinDependency#relation too?
226
- #def relation
227
- # # NOTE: This cannot be @relation as ActiveRecord already uses this to
228
- # # cache *its* Relation object
229
- # @_geokit_relation ||= Relation.new(self, arel_table)
230
- # finder_needs_type_condition? ? @_geokit_relation.where(type_condition) : @_geokit_relation
231
- #end
232
-
233
- # If it's a :within query, add a bounding box to improve performance.
234
- # This only gets called if a :bounds argument is not otherwise supplied.
235
- def formulate_bounds_from_distance(options, origin, units)
236
- distance = options[:within] if options.has_key?(:within)
237
- distance = options[:range].last-(options[:range].exclude_end?? 1 : 0) if options.has_key?(:range)
238
- if distance
239
- Geokit::Bounds.from_point_and_radius(origin,distance,:units=>units)
240
- else
241
- nil
242
- end
243
- end
244
-
245
- def distance_conditions(options)
246
- origin = extract_origin_from_options(options)
247
- units = extract_units_from_options(options)
248
- formula = extract_formula_from_options(options)
249
- distance_column_name = distance_sql(origin, units, formula)
250
-
251
- res = if options.has_key?(:within)
252
- "#{distance_column_name} <= #{options[:within]}"
253
- elsif options.has_key?(:beyond)
254
- "#{distance_column_name} > #{options[:beyond]}"
255
- elsif options.has_key?(:range)
256
- "#{distance_column_name} >= #{options[:range].first} AND #{distance_column_name} <#{'=' unless options[:range].exclude_end?} #{options[:range].last}"
257
- end
258
- Arel::Nodes::SqlLiteral.new("(#{res})") if res.present?
259
- end
260
-
261
- def bound_conditions(bounds)
262
- sw,ne = bounds.sw, bounds.ne
263
- lng_sql = bounds.crosses_meridian? ? "(#{qualified_lng_column_name}<#{ne.lng} OR #{qualified_lng_column_name}>#{sw.lng})" : "#{qualified_lng_column_name}>#{sw.lng} AND #{qualified_lng_column_name}<#{ne.lng}"
264
- res = "#{qualified_lat_column_name}>#{sw.lat} AND #{qualified_lat_column_name}<#{ne.lat} AND #{lng_sql}"
265
- #Arel::Nodes::SqlLiteral.new("(#{res})") if res.present?
266
- res if res.present?
267
- end
268
-
269
- # Extracts the origin instance out of the options if it exists and returns
270
- # it. If there is no origin, looks for latitude and longitude values to
271
- # create an origin. The side-effect of the method is to remove these
272
- # option keys from the hash.
273
- def extract_origin_from_options(options)
274
- origin = options.delete(:origin)
275
- res = normalize_point_to_lat_lng(origin) if origin
276
- res
277
- end
278
-
279
- # Extract the units out of the options if it exists and returns it. If
280
- # there is no :units key, it uses the default. The side effect of the
281
- # method is to remove the :units key from the options hash.
282
- def extract_units_from_options(options)
283
- units = options[:units] || default_units
284
- options.delete(:units)
285
- units
286
- end
287
-
288
- # Extract the formula out of the options if it exists and returns it. If
289
- # there is no :formula key, it uses the default. The side effect of the
290
- # method is to remove the :formula key from the options hash.
291
- def extract_formula_from_options(options)
292
- formula = options[:formula] || default_formula
293
- options.delete(:formula)
294
- formula
295
- end
296
-
297
- def extract_bounds_from_options(options)
298
- bounds = options.delete(:bounds)
299
- bounds = Geokit::Bounds.normalize(bounds) if bounds
300
- end
301
-
302
- # Geocode IP address.
303
- def geocode_ip_address(origin)
304
- geo_location = Geokit::Geocoders::MultiGeocoder.geocode(origin)
305
- return geo_location if geo_location.success
306
- raise Geokit::Geocoders::GeocodeError
307
- end
308
-
309
- # Given a point in a variety of (an address to geocode,
310
- # an array of [lat,lng], or an object with appropriate lat/lng methods, an IP addres)
311
- # this method will normalize it into a Geokit::LatLng instance. The only thing this
312
- # method adds on top of LatLng#normalize is handling of IP addresses
313
- def normalize_point_to_lat_lng(point)
314
- res = geocode_ip_address(point) if point.is_a?(String) && /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(point)
315
- res = Geokit::LatLng.normalize(point) unless res
316
- res
317
- end
318
-
319
- # Looks for the distance column and replaces it with the distance sql. If an origin was not
320
- # passed in and the distance column exists, we leave it to be flagged as bad SQL by the database.
321
- # Conditions are either a string or an array. In the case of an array, the first entry contains
322
- # the condition.
323
- def substitute_distance_in_where_values(arel, origin, units=default_units, formula=default_formula)
324
- pattern = Regexp.new("\\b#{distance_column_name}\\b")
325
- value = distance_sql(origin, units, formula)
326
- arel.where_values.map! do |where_value|
327
- if where_value.is_a?(String)
328
- where_value.gsub(pattern, value)
329
- else
330
- where_value
331
- end
332
- end
333
- arel
334
- end
335
-
336
- # Returns the distance SQL using the spherical world formula (Haversine). The SQL is tuned
337
- # to the database in use.
338
- def sphere_distance_sql(origin, units)
339
- # "origin" can be a Geokit::LatLng (with :lat and :lng methods), e.g.
340
- # when using geo_scope or it can be an ActsAsMappable with customized
341
- # latitude and longitude methods, e.g. when using distance_sql.
342
- lat = deg2rad(get_lat(origin))
343
- lng = deg2rad(get_lng(origin))
344
- multiplier = units_sphere_multiplier(units)
345
- geokit_finder_adapter.sphere_distance_sql(lat, lng, multiplier) if geokit_finder_adapter
346
- end
347
-
348
- # Returns the distance SQL using the flat-world formula (Phythagorean Theory). The SQL is tuned
349
- # to the database in use.
350
- def flat_distance_sql(origin, units)
351
- lat_degree_units = units_per_latitude_degree(units)
352
- lng_degree_units = units_per_longitude_degree(get_lat(origin), units)
353
- geokit_finder_adapter.flat_distance_sql(origin, lat_degree_units, lng_degree_units)
354
- end
355
-
356
- def get_lat(origin)
357
- origin.respond_to?(:lat) ? origin.lat \
358
- : origin.send(:"#{lat_column_name}")
359
- end
360
-
361
- def get_lng(origin)
362
- origin.respond_to?(:lng) ? origin.lng \
363
- : origin.send(:"#{lng_column_name}")
364
- end
365
-
366
- end # ClassMethods
367
-
368
43
  # this is the callback for auto_geocoding
369
44
  def auto_geocode_address
370
45
  address=self.send(auto_geocode_field).to_s
@@ -401,7 +76,3 @@ module Geokit
401
76
 
402
77
  end # ActsAsMappable
403
78
  end # Geokit
404
-
405
-
406
-
407
- # ActiveRecord::Base.extend Geokit::ActsAsMappable
@@ -3,7 +3,7 @@ module Geokit
3
3
  class SQLite < Abstract
4
4
 
5
5
  def self.add_numeric(name)
6
- @@connection.create_function name, 1, :numeric do |func, *args|
6
+ @@connection.create_function name, 1, SQLite3::Constants::TextRep::ANY do |func, *args|
7
7
  func.result = yield(*args)
8
8
  end
9
9
  end
@@ -50,4 +50,4 @@ module Geokit
50
50
 
51
51
  end
52
52
  end
53
- end
53
+ end
@@ -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
- if respond_to? :before_action
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].to_yaml, :expires => 30.days.from_now } if 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
@@ -1,3 +1,3 @@
1
1
  module GeokitRails
2
- VERSION = "2.3.1"
2
+ VERSION = "2.5.0"
3
3
  end
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/core_extensions'
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'
@@ -108,6 +108,12 @@ class ActsAsMappableTest < GeokitTestCase
108
108
  assert_equal 5, locations.count
109
109
  end
110
110
 
111
+ def test_find_within_with_column_as_distance
112
+ locations = Location.joins(:company).within(Company.arel_table[:max_distance], origin: @loc_a)
113
+ assert_equal 4, locations.to_a.size
114
+ assert_equal 4, locations.count
115
+ end
116
+
111
117
  def test_find_with_compound_condition
112
118
  #locations = Location.geo_scope(:origin => @loc_a).where("distance < 5 and city = 'Coppell'")
113
119
  locations = Location.within(5, :origin => @loc_a).where("city = 'Coppell'")
@@ -383,6 +389,16 @@ class ActsAsMappableTest < GeokitTestCase
383
389
  assert_equal 2, locations.count
384
390
  end
385
391
 
392
+ def test_find_within_bounds_with_inclusive
393
+ sw = Geokit::LatLng.new(@loc_a.lat,@loc_a.lng)
394
+ ne = sw
395
+ bounds = [sw,ne]
396
+ locations = Location.in_bounds(bounds, :inclusive => false)
397
+ assert_equal 0, locations.count
398
+ locations = Location.in_bounds(bounds, :inclusive => true)
399
+ assert_equal 1, locations.count
400
+ end
401
+
386
402
  def test_find_within_bounds_ordered_by_distance
387
403
  #locations = Location.in_bounds([@sw,@ne], :origin=>@bounds_center).order('distance asc')
388
404
  locations = Location.in_bounds([@sw,@ne]).by_distance(:origin => @bounds_center)
@@ -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
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative "config/application"
5
+
6
+ Rails.application.load_tasks
File without changes
@@ -0,0 +1 @@
1
+ /* Application styles */
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Connection < ActionCable::Connection::Base
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ attr_accessor :remote_ip
3
+ end
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,2 @@
1
+ module ApplicationHelper
2
+ 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
@@ -0,0 +1,4 @@
1
+ class ApplicationMailer < ActionMailer::Base
2
+ default from: "from@example.com"
3
+ layout "mailer"
4
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationRecord < ActiveRecord::Base
2
+ primary_abstract_class
3
+ 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,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
+ <style>
6
+ /* Email styles need to be inline */
7
+ </style>
8
+ </head>
9
+
10
+ <body>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
@@ -0,0 +1 @@
1
+ <%= yield %>
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path("../config/application", __dir__)
3
+ require_relative "../config/boot"
4
+ require "rails/commands"
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative "../config/boot"
3
+ require "rake"
4
+ Rake.application.run
@@ -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