geokit-rails 2.3.1 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
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