geokit-rails 2.0.1 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of geokit-rails might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MjQ2ZjFiYzY3ZGE3M2Y3N2Q0YWVkM2Q2ZjdmMGZhNDllZWE1YzY4MA==
5
- data.tar.gz: !binary |-
6
- OGI2ZDcxN2QzMWMzNWM0YzIxMzYxYTlkYmYyNDU3MjE5MWM5MmY1Yg==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- Yzk2Yjc2ODE2NzU3NmQ2OWRjMWIxOGQ5NmVkODUxZmY5MzlhNzkxMjM2MGFm
10
- Mjg0ODY3NzBiNDdjMWIxODZkM2E4NWYzZDliYmI1NmJlNzA1Y2ExNjM5ZmZl
11
- OWE3N2ZkN2ViYWNmYzU4NmU2NWQ4MjVjYzI1MjdiYzViZTNlNTY=
12
- data.tar.gz: !binary |-
13
- ZGI0ZTBmMTYyZGU0MDA0MTZmYmJmMzYyMjY2OTJjNjQzMmI5YmVmNWZkMTg4
14
- ZDQwODU5OWMzNGJkNWVlMWJiOWU2NDkwYmEwYTI1NmQ5YTQ2ZDQ0YmMxNGVh
15
- ODRhMDMxNDAyYzljNThkZWEzMmJlYjljNzc2ZjU5NWM5ODE0M2U=
2
+ SHA256:
3
+ metadata.gz: d8abd196ef01725dfea499611d751fe08d1f42da5473c7896d526b16044e5c7a
4
+ data.tar.gz: aef079a740792c981bb86d07d48c3686b2d939d5ce1792dd50d7d5c4bfe6bc05
5
+ SHA512:
6
+ metadata.gz: 7de113ad53d0ae12a3919337e70ec69d91a59f1ae9147235ee2eb42ccdd20e73438784bba5eb6122da7bb1185e28cd8d321af7a63c654b153ead266ac96d548b
7
+ data.tar.gz: ad3e5699a610b9ef8ef451bd76bef841f36272a96896a04c2610d8cb21603f869a0c670a4754366d8b3df5dc13e3f03a3807f9a96848abe63ae0e30aa45b40e9
@@ -0,0 +1,37 @@
1
+ # Bundler
2
+ # http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
3
+ Gemfile.lock
4
+
5
+ # Test log files
6
+ test/*-debug.log
7
+
8
+ # SQLite Test DB
9
+ test/test.sqlite3
10
+
11
+ # SVN
12
+ .svn
13
+
14
+ # RVM
15
+ .rvmrc
16
+
17
+ # TextMate
18
+ *.tmproj
19
+
20
+ # rcov generated
21
+ coverage
22
+
23
+ # rdoc generated
24
+ rdoc
25
+
26
+ # yard generated
27
+ doc
28
+ .yardoc
29
+
30
+ # bundler
31
+ .bundle
32
+
33
+ # builds
34
+ *.gem
35
+
36
+ # For MacOS:
37
+ .DS_Store
@@ -0,0 +1,29 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0
4
+ - 2.1
5
+ - 2.2
6
+ - 2.3
7
+ - 2.4
8
+ gemfile:
9
+ - gemfiles/rails3.gemfile
10
+ - gemfiles/rails4.gemfile
11
+ - gemfiles/rails5.gemfile
12
+ matrix:
13
+ exclude:
14
+ - rvm: 2.2
15
+ gemfile: gemfiles/rails3.gemfile
16
+ - rvm: 2.3
17
+ gemfile: gemfiles/rails3.gemfile
18
+ - rvm: 2.4
19
+ gemfile: gemfiles/rails3.gemfile
20
+ - rvm: 2.0
21
+ gemfile: gemfiles/rails5.gemfile
22
+ - rvm: 2.1
23
+ gemfile: gemfiles/rails5.gemfile
24
+ script: "bundle exec rake coverage"
25
+ before_install:
26
+ - gem install bundler
27
+ bundler_args: --retry 5
28
+ sudo: false
29
+ cache: bundler
@@ -0,0 +1,96 @@
1
+ ## 2.3.2
2
+
3
+ * Fix sqlite3 adapter error
4
+
5
+ ## 2.3.1
6
+
7
+ * Fix Rails 5.2 deprecation warning
8
+
9
+ ## 2.3.0
10
+
11
+ * Drop ruby 1.9 and add 2.3 support
12
+ * Add an option to skip loading
13
+ * Remove excessive debug statement
14
+
15
+ ## 2.2.0
16
+
17
+ * Add rails config aenerator
18
+ * Add NOT NULL checks for latitude and longitude, otherwise nonsense
19
+ values are being returned for distance calculations involving such
20
+ objects.
21
+ * Fix inconsistent case where retrieve_location_from_cookie_or_services
22
+ returned a Hash instead of a GeoLoc
23
+ * Speed up SQL with bounding box
24
+ * Tests against rails 4 & 5
25
+
26
+ ## 2.1.0
27
+
28
+ * Add OracleEnhanced adapter
29
+ * Fix bug with custom latitude/longitude names
30
+ * BREAKING: Nearest and fathest return scopes not arrays
31
+ * Drop support for ruby 1.8/1.9
32
+
33
+ ## 2.0.1
34
+
35
+ * Fix GeoKit naming compatibility
36
+
37
+ ## 2.0.0 / 2013-06-19
38
+
39
+ * Integrated geokit-rails3 into geokit-rails (use 1.x for rails2 support)
40
+
41
+ ## 1.2.0 / 2009-10-02
42
+
43
+ * Overhaul the test suite to be independent of a Rails project
44
+ * Added concept of database adapter. Ported mysql/postgresql conditional code to their own adapter.
45
+ * Added SQL Server support. THANKS http://github.com/brennandunn for all the improvements in this release
46
+
47
+ ## 1.1.3 / 2009-09-26
48
+
49
+ * documentation updates and updated to work with Geokit gem v1.5.0
50
+ * IMPORTANT: in the Geokit gem, Geokit::Geocoders::timeout became Geokit::Geocoders::request_timeout for jruby compatibility.
51
+ The plugin sets this in config/initializers/geokit_config.rb. So if you've upgraded the gem to 1.5.0, you need to
52
+ make the change manually from Geokit::Geocoders::timeout to Geokit::Geocoders::request_timeout in config/initializers/geokit_config.rb
53
+
54
+ ## 1.1.2 / 2009-06-08
55
+
56
+ * Added support for hashes in :through. So you can do: acts_as_mappable :through => { :state => :country } (Thanks José Valim).
57
+
58
+ ## 1.1.1 / 2009-05-22
59
+ * Support for multiple ip geocoders (Thanks dreamcat4)
60
+ * Now checks if either :origin OR :bounds is passed, and proceeds with geokit query if this is true (Thanks Glenn Powell)
61
+ * Raises a helpful error if someone uses through but the association does not exists or was not defined yet (Thanks José Valim)
62
+
63
+ ## 1.1.0 / 2009-04-11
64
+
65
+ * Fixed :through usages so that the through model is only included in the query if there
66
+ is an :origin passed in (Only if it is a geokit search) (Thanks Glenn Powell)
67
+ * Move library initialisation into lib/geokit-rails. init.rb uses lib/geokit-rails now (thanks Alban Peignier)
68
+ * Handle the case where a user passes a hash to the :conditions Finder option (thanks Adam Greene)
69
+ * Added ability to specify domain-specific API keys (Thanks Glenn Powell)
70
+
71
+ ## 2009-02-20
72
+
73
+ * More powerful assosciations in the Rails Plugin:You can now specify a model as mappable "through" an associated model.
74
+ In other words, that associated model is the actual mappable model with "lat" and "lng" attributes, but this "through" model
75
+ can still utilize all Geokit's "find by distance" finders. Also Rails 2.3 compatibility (thanks github/glennpow)
76
+
77
+ ## 2008-12-18
78
+
79
+ * Split Rails plugin from geocoder gem
80
+ * updated for Rails 2.2.2
81
+
82
+ ## 2008-08-20
83
+
84
+ * Further fix of distance calculation, this time in SQL. Now uses least() function, which is available in MySQL version 3.22.5+ and postgres versions 8.1+
85
+
86
+ ## 2008-01-16
87
+
88
+ * fixed the "zero-distance" bug (calculating between two points that are the same)
89
+
90
+ ## 2007-11-12
91
+
92
+ * fixed a small but with queries crossing meridian, and also fixed find(:closest)
93
+
94
+ ## 2007-10-11
95
+
96
+ * Fixed Rails2/Edge compatability
@@ -0,0 +1,67 @@
1
+ # You can configure Geokit in your environment files
2
+
3
+ These defaults are used in `Geokit::Mappable.distance_to` and in `acts_as_mappable`
4
+
5
+ config.geokit.default_units = :miles
6
+ config.geokit.default_formula = :sphere
7
+
8
+ This is the timeout value in seconds to be used for calls to the geocoder web services. For no timeout at all, comment out the setting. The timeout unit is in seconds.
9
+
10
+ config.geokit.geocoders.request_timeout = 3
11
+
12
+ These settings are used if web service calls must be routed through a proxy.
13
+ These setting can be `nil` if not needed, otherwise, addr and port must be filled in at a minimum. If the proxy requires authentication, the username and password can be provided as well.
14
+
15
+ config.geokit.geocoders.proxy_addr = nil
16
+ config.geokit.geocoders.proxy_port = nil
17
+ config.geokit.geocoders.proxy_user = nil
18
+ config.geokit.geocoders.proxy_pass = nil
19
+
20
+ This is your yahoo application key for the Yahoo Geocoder.
21
+
22
+ See [http://developer.yahoo.com/faq/index.html#appid](http://developer.yahoo.com/faq/index.html#appid)
23
+ and [http://developer.yahoo.com/maps/rest/V1/geocode.html](http://developer.yahoo.com/maps/rest/V1/geocode.html)
24
+
25
+ config.geokit.geocoders.yahoo = 'REPLACE_WITH_YOUR_YAHOO_KEY'
26
+
27
+ This is your Google Maps geocoder key.
28
+
29
+ See [http://www.google.com/apis/maps/signup.html](http://www.google.com/apis/maps/signup.html)
30
+ and [http://www.google.com/apis/maps/documentation/#Geocoding_Examples](http://www.google.com/apis/maps/documentation/#Geocoding_Examples)
31
+
32
+ config.geokit.geocoders.google = 'REPLACE_WITH_YOUR_GOOGLE_KEY'
33
+
34
+ This is your username and password for **geocoder.us**.
35
+ To use the free service, the value can be set to `nil` or `false`.
36
+ For usage tied to an account, the value should be set to `username:password`.
37
+
38
+ See [http://geocoder.us](http://geocoder.us)
39
+ and [http://geocoder.us/user/signup](http://geocoder.us/user/signup)
40
+
41
+ config.geokit.geocoders.geocoder_us = false
42
+
43
+ This is your authorization key for **geocoder.ca**.
44
+ To use the free service, the value can be set to `nil` or `false`. For usage tied to an account, set the value to the key obtained from
45
+ **Geocoder.ca**.
46
+
47
+ See [http://geocoder.ca](http://geocoder.ca)
48
+ and [http://geocoder.ca/?register=1](http://geocoder.ca/?register=1)
49
+
50
+ config.geokit.geocoders.geocoder_ca = false
51
+
52
+ Add this to use a username with the Geonames geocoder
53
+
54
+ config.geokit.geocoders.geonames="REPLACE_WITH_YOUR_GEONAMES_USERNAME"
55
+
56
+ This is the order in which the geocoders are called in a failover scenario.
57
+ If you only want to use a single geocoder, put a single symbol in the array.
58
+ Valid symbols are `:google`, `:yahoo`, `:us`, and `:ca`.
59
+ Be aware that there are **Terms of Use** restrictions on how you can use the various geocoders. Make sure you read up on relevant **Terms of Use** for each geocoder you are going to use.
60
+
61
+ config.geokit.geocoders.provider_order = [:google,:us]
62
+
63
+ The IP provider order. Valid symbols are `:ip`, `:geo_plugin`.
64
+ As before, make sure you read up on relevant **Terms of Use** for each
65
+
66
+ config.geokit.geocoders.ip_provider_order = [:geo_plugin,:ip]
67
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Michael Noack, James Cox, Bill Eisenhauer & Andre Lewis
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,726 @@
1
+ Geokit Rails
2
+ ============
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/geokit-rails.png)](http://badge.fury.io/rb/geokit-rails)
5
+ [![Build Status](https://travis-ci.org/geokit/geokit-rails.png?branch=master)](https://travis-ci.org/geokit/geokit-rails)
6
+ [![Coverage Status](https://coveralls.io/repos/geokit/geokit-rails/badge.png?branch=master)](https://coveralls.io/r/geokit/geokit-rails)
7
+ [![Dependency Status](https://gemnasium.com/geokit/geokit-rails.png?travis)](https://gemnasium.com/geokit/geokit-rails)
8
+ [![Code Climate](https://codeclimate.com/github/geokit/geokit-rails.png)](https://codeclimate.com/github/geokit/geokit-rails)
9
+
10
+ ## COMMUNICATION
11
+
12
+ * If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/geokit). (Tag 'geokit' and we'll be alerted)
13
+ * If you **found a bug**, use GitHub issues.
14
+ * If you **have an idea**, use GitHub issues.
15
+ * If you'd like to **ask a general question**, use GitHub issues.
16
+ * If you **want to contribute**, submit a pull request.
17
+
18
+ ## INSTALLATION
19
+
20
+ Geokit for Rails consists of a generic Gem ([geokit](https://github.com/geokit/geokit)) and a Rails plugin ([geokit-rails](https://github.com/geokit/geokit-rails)).
21
+
22
+ Make sure you use a version >= 3.0 of Rails.
23
+
24
+ You just have to add the 'geokit-rails' gem to your Gemfile
25
+
26
+ ```ruby
27
+ gem 'geokit-rails'
28
+ ```
29
+
30
+ Then tell bundler to update the gems :
31
+
32
+ ```sh
33
+ $ bundle install
34
+ ```
35
+ Generate the configuration initializer:
36
+
37
+ ```sh
38
+ $ rails g geokit_rails:install
39
+ ```
40
+
41
+ Now, if you wish to use the various geocoding services, you can add your keys to the new initializer.
42
+
43
+
44
+
45
+ If you want to use geokit-rails in a Rails 2 application, just use the good old plugin ([geokit-rails](https://github.com/andre/geokit-rails)).
46
+
47
+
48
+ ## FEATURE SUMMARY
49
+
50
+ Geokit provides key functionality for location-oriented Rails applications:
51
+
52
+ - Distance calculations, for both flat and spherical environments. For example,
53
+ given the location of two points on the earth, you can calculate the miles/Km
54
+ between them.
55
+ - ActiveRecord distance-based finders. For example, you can find all the points
56
+ in your database within a 50-mile radius.
57
+ - IP-based location lookup utilizing hostip.info. Provide an IP address, and get
58
+ city name and latitude/longitude in return
59
+ - A before_action helper to geocoder the user's location based on IP address,
60
+ and retain the location in a cookie.
61
+ - Geocoding from multiple providers. It provides a fail-over mechanism, in case
62
+ your input fails to geocode in one service. Geocoding is provided by the Geokit
63
+ gem, which you must have installed
64
+
65
+ The goal of this plugin is to provide the common functionality for location-oriented
66
+ applications (geocoding, location lookup, distance calculation) in an easy-to-use
67
+ package.
68
+
69
+ ## A NOTE ON TERMINOLOGY
70
+
71
+ Throughout the code and API, _latitude_ and _longitude_ are referred to as _lat_
72
+ and _lng_. We've found over the long term the abbreviation saves lots of typing time.
73
+
74
+ ## LOCATION QUERIES
75
+
76
+ ### MAKING A MODEL MAPPABLE
77
+
78
+ To get started, just specify an ActiveRecord class as `acts_as_mappable`:
79
+
80
+ ```ruby
81
+ class Location < ActiveRecord::Base
82
+ acts_as_mappable
83
+ end
84
+ ```
85
+
86
+ There are some defaults you can override:
87
+
88
+ ```ruby
89
+ class Location < ActiveRecord::Base
90
+ acts_as_mappable :default_units => :miles,
91
+ :default_formula => :sphere,
92
+ :distance_field_name => :distance,
93
+ :lat_column_name => :lat,
94
+ :lng_column_name => :lng
95
+ end
96
+ ```
97
+
98
+ The optional parameters are `units`, `formula`, and `distance_field_name`.
99
+ Values for **units** can be `:miles`, `:kms` (kilometers), or `:nms` (nautical miles),
100
+ with `:miles` as the default.
101
+ Values for **formula** can be `:sphere` or `:flat` with `:sphere` as the default.
102
+ `:sphere` gives you Haversine calculations, while `:flat` gives the Pythagoreum Theory.
103
+ These defaults persist through out the gem.
104
+
105
+ The plug-in creates a calculated `distance` field on AR instances that have
106
+ been retrieved through a Geokit location query. By default, these fields are
107
+ known as "distance" but this can be changed through the `:distance_field_name` key.
108
+
109
+ You can also define alternative column names for latitude and longitude using
110
+ the `:lat_column_name` and `:lng_column_name` keys. The defaults are `lat` and
111
+ `lng` respectively.
112
+
113
+ ### NEW SCOPES TO USE
114
+
115
+ Once you've specified `acts_as_mappable`, a few scopes are available :
116
+
117
+ * `within` and `beyond` find records within or beyond a certain distance from the origin point.
118
+ * `in_range` finds records within a certain distance range from the origin point.
119
+ * `in_bounds` finds records within a rectangle on the map
120
+ * `closest` and `farthest` find the closest or farthest record from the origin point
121
+ * `by_distance` finds records ordered by distance from the origin point
122
+
123
+ All of these scopes take a hash of options where the first parameter is simply
124
+ one of the possible options, without the name.
125
+
126
+ A few examples :
127
+
128
+ ```ruby
129
+ Location.within(5, :origin => @somewhere)
130
+ ```
131
+
132
+ ```ruby
133
+ Location.in_range(2..5, :origin => @somewhere)
134
+ ```
135
+
136
+ ```ruby
137
+ Location.in_bounds([@south_west_point, @north_east_point], :origin => @somewhere)
138
+ ```
139
+
140
+ The options can be :
141
+
142
+ `:origin` as a two-element array of latitude/longitude:
143
+
144
+ ```ruby
145
+ Location.by_distance(:origin => [37.792,-122.393])
146
+ ```
147
+
148
+ `:origin` as a geocodeable string:
149
+
150
+ ```ruby
151
+ Location.by_distance(:origin => '100 Spear st, San Francisco, CA')
152
+ ```
153
+
154
+ `:origin` as an object which responds to `lat` and `lng` methods,
155
+ or `latitude` and `longitude` methods, or whatever methods you have
156
+ specified for `lng_column_name` and `lat_column_name`:
157
+
158
+ ```ruby
159
+ Location.geo_scope(:origin => my_store)
160
+ # my_store.lat and my_store.lng methods exist
161
+ ```
162
+
163
+ `:units` or `:formula` can be used to override the default values in a specific query
164
+
165
+ ```ruby
166
+ Location.within(5, :units => :kms, :origin => @somewhere)
167
+ # it will get the records within 5 kilometers instead of 5 miles
168
+ ```
169
+
170
+ `:range` as a native Ruby range
171
+
172
+ `:bounds` as an array of two elements : the south/west point and the north/east point.
173
+
174
+ ```ruby
175
+ @sw = Geokit::LatLng.new(32.91663,-96.982841)
176
+ @ne = Geokit::LatLng.new(32.96302,-96.919495)
177
+ @somewhere = Location.find(123456)
178
+ Location.within(:bounds => [@sw, @ne], :origin => @somewhere)
179
+ ```
180
+
181
+ `:bounds` as a Geokit::Bounds object
182
+
183
+ ```ruby
184
+ @bounds = Geokit::Bounds.new([32.91663,-96.982841], [32.96302,-96.919495])
185
+ @somewhere = Location.find(123456)
186
+ Location.within(:bounds => [@sw, @ne], :origin => @somewhere)
187
+ ```
188
+
189
+ When using a point of reference or bounds, you leverage the power of Geokit
190
+ to build this objects. Basically, if Geokit can make a Geokit::Point
191
+ or a Geokit::Bounds with what you give to it, you're good to go.
192
+
193
+ ### FIND BY SQL
194
+
195
+ Finally, if all that is desired is the raw SQL for distance
196
+ calculations, you can use the following:
197
+
198
+ ```ruby
199
+ Location.distance_sql(origin, units = default_units, formula = default_formula)
200
+ ```
201
+
202
+ Thereafter, you are free to use it in `find_by_sql` as you wish.
203
+
204
+ ### CHAINABILITY
205
+
206
+ You can then chain these scope with any other or use a "calling" method like `first`, `all`, `count`, …
207
+
208
+ ```ruby
209
+ Location.within(5, :origin => @somewhere).all
210
+ Location.within(5, :origin => @somewhere).count
211
+ Location.by_distance(:origin => [37.792,-122.393]).first
212
+ ```
213
+
214
+ You can add `order` clauses in the chain as for any ActiveRecord query
215
+
216
+ ```ruby
217
+ Location.within(5, :origin => @somewhere).order('nbr_seats ASC')
218
+ ```
219
+
220
+ You can even sort by distance (use the same name as specified in the model class)
221
+
222
+ ```ruby
223
+ Location.within(5, :origin => @somewhere).order('distance DESC, nbr_seats ASC')
224
+ ```
225
+
226
+ Idem for the `limit` clause. In fact, `closest` and `farthest` are defined like this :
227
+
228
+ ```ruby
229
+ def closest(options = {})
230
+ by_distance(options).limit(1)
231
+ end
232
+ def farthest(options = {})
233
+ by_distance({:reverse => true}.merge(options)).limit(1)
234
+ end
235
+ ```
236
+
237
+ #### Important caveat
238
+
239
+ In the current version of geokit-rails, it is not possible to add a `where` clause
240
+ using the _distance_ column. I've tried many different ways to do this and didn't get it working.
241
+
242
+ One would expect to build a query like this :
243
+
244
+ ```ruby
245
+ scoped = Location.by_distance(:origin => @somewhere)
246
+ scoped = scoped.where('distance <= 5')
247
+ results = scoped.all
248
+ ```
249
+
250
+ This is not possible right now, it must be done in a single step like this :
251
+
252
+ ```ruby
253
+ scoped = Location.within(5, :origin => @somewhere)
254
+ results = scoped.all
255
+ ```
256
+
257
+ Every good idea that would help achieve this is very much welcome.
258
+
259
+ ### FINDING WITHIN A BOUNDING BOX
260
+
261
+ If you are displaying points on a map, you probably need to query for whatever falls within the rectangular bounds of the map:
262
+
263
+ ```ruby
264
+ Store.in_bounds([sw_point,ne_point]).all
265
+ ```
266
+
267
+ If you want the query to return things that are located on the rectangular bounds, specify the `inclusive` option set to true:
268
+
269
+ ```ruby
270
+ Store.in_bounds([sw_point,ne_point], :inclusive => true).all
271
+ ```
272
+
273
+ The input to `bounds` can be an array with the two points or a Bounds object. However you provide them, the order should always be the southwest corner, northeast corner of the rectangle. Typically, you will be getting the sw\_point and ne\_point from a map that is displayed on a web page.
274
+
275
+ If you need to calculate the bounding box from a point and radius, you can do that:
276
+
277
+ ```ruby
278
+ bounds = Geokit::Bounds.from_point_and_radius(home,5)
279
+ Store.in_bounds(bounds).all
280
+ ```
281
+
282
+ ----
283
+
284
+ # What is following is from the previous _geokit-rails_ plugin.
285
+
286
+ > **It has not been tested with Rails 3 nor with this version of the gem.**
287
+ **Most of it should work, but it is not sure**
288
+
289
+
290
+ ## USING INCLUDES
291
+
292
+ You can use includes along with your distance finders:
293
+
294
+ ```ruby
295
+ stores = Store.within(5, :origin=>home).includes([:reviews,:cities]).order('distance asc').all
296
+ ```
297
+
298
+ *However*, ActiveRecord drops the calculated distance column when you use include. So, if you need to use the distance column, you'll have to re-calculate it post-query in Ruby:
299
+
300
+ ```ruby
301
+ stores.sort_by{|s| s.distance_to(home)}
302
+ ```
303
+
304
+ In this case, you may want to just use the bounding box condition alone in your SQL (there's no use calculating the distance twice):
305
+
306
+ ```ruby
307
+ bounds=Geokit::Bounds.from_point_and_radius(home,5)
308
+ stores=Store.includes([:reviews,:cities]).in_bounds(bounds)
309
+ stores.sort_by{|s| s.distance_to(home)}
310
+ ```
311
+
312
+ ## USING :through
313
+
314
+ You can also specify a model as mappable "through" another associated model. In other words, that associated model is the actual mappable model with "lat" and "lng" attributes, but this "through" model can still utilize all of the above find methods to search for records.
315
+
316
+ ```ruby
317
+ class Location < ActiveRecord::Base
318
+ belongs_to :locatable, :polymorphic => true
319
+ acts_as_mappable
320
+ end
321
+ ```
322
+
323
+ ```ruby
324
+ class Company < ActiveRecord::Base
325
+ has_one :location, :as => :locatable # also works for belongs_to associations
326
+ acts_as_mappable :through => :location
327
+ end
328
+ ```
329
+
330
+ Then you can still call:
331
+
332
+ ```ruby
333
+ Company.within(distance, :origin => @somewhere)
334
+ ```
335
+
336
+ You can also give :through a hash if your location is nested deep. For example, given:
337
+
338
+ ```ruby
339
+ class House
340
+ acts_as_mappable
341
+ end
342
+ ```
343
+
344
+ ```ruby
345
+ class Family
346
+ belongs_to :house
347
+ end
348
+ ```
349
+
350
+ ```ruby
351
+ class Person
352
+ belongs_to :family
353
+ acts_as_mappable :through => { :family => :house }
354
+ end
355
+ ```
356
+
357
+ Remember that the notes above about USING INCLUDES apply to the results from
358
+ this find, since an include is automatically used.
359
+
360
+ ## IP GEOCODING
361
+
362
+ You can obtain the location for an IP at any time using the geocoder
363
+ as in the following example:
364
+
365
+ ```ruby
366
+ location = IpGeocoder.geocode('12.215.42.19')
367
+ ```
368
+
369
+ where Location is a GeoLoc instance containing the latitude,
370
+ longitude, city, state, and country code. Also, the success
371
+ value is true.
372
+
373
+ If the IP cannot be geocoded, a GeoLoc instance is returned with a
374
+ success value of false.
375
+
376
+ It should be noted that the IP address needs to be visible to the
377
+ Rails application. In other words, you need to ensure that the
378
+ requesting IP address is forwarded by any front-end servers that
379
+ are out in front of the Rails app. Otherwise, the IP will always
380
+ be that of the front-end server.
381
+
382
+ The Multi-Geocoder will also geocode IP addresses and provide
383
+ failover among multiple IP geocoders. Just pass in an IP address for the
384
+ parameter instead of a street address. Eg:
385
+
386
+ ```ruby
387
+ location = Geocoders::MultiGeocoder.geocode('12.215.42.19')
388
+ ```
389
+
390
+ The MultiGeocoder class requires 2 configuration setting for the provider order.
391
+ Ordering is done through `Geokit::Geocoders::provider_order` and
392
+ `Geokit::Geocoders::ip_provider_order`, found in
393
+ `config/initializers/geokit_config.rb`. If you don't already have a
394
+ `geokit_config.rb` file, the plugin creates one when it is first installed.
395
+
396
+
397
+ ## IP GEOCODING HELPER
398
+
399
+ A class method called geocode_ip_address has been mixed into the
400
+ ActionController::Base. This enables before_action style lookup of
401
+ the IP address. Since it is a filter, it can accept any of the
402
+ available filter options.
403
+
404
+ Usage is as below:
405
+
406
+ ```ruby
407
+ class LocationAwareController < ActionController::Base
408
+ geocode_ip_address
409
+ end
410
+ ```
411
+
412
+ A first-time lookup will result in the GeoLoc class being stored
413
+ in the session as `:geo_location` as well as in a cookie called
414
+ `:geo_session`. Subsequent lookups will use the session value if it
415
+ exists or the cookie value if it doesn't exist. The last resort is
416
+ to make a call to the web service. Clients are free to manage the
417
+ cookie as they wish.
418
+
419
+ The intent of this feature is to be able to provide a good guess as
420
+ to a new visitor's location.
421
+
422
+ ## INTEGRATED FIND AND GEOCODING
423
+
424
+ Geocoding has been integrated with the finders enabling you to pass
425
+ a physical address or an IP address. This would look the following:
426
+
427
+ ```ruby
428
+ Location.farthest(:origin => '217.15.10.9')
429
+ Location.farthest(:origin => 'Irving, TX')
430
+ ```
431
+
432
+ where the IP or physical address would be geocoded to a location and
433
+ then the resulting latitude and longitude coordinates would be used
434
+ in the find. This is not expected to be common usage, but it can be
435
+ done nevertheless.
436
+
437
+ ## ADDRESS GEOCODING
438
+
439
+ Geocoding is provided by the Geokit gem, which is required for this plugin.
440
+ See the top of this file for instructions on installing the Geokit gem.
441
+
442
+ Geokit can geocode addresses using multiple geocodeing web services.
443
+ Geokit supports services like Google, Yahoo, and Geocoder.us, and more --
444
+ see the Geokit gem API for a complete list.
445
+
446
+ These geocoder services are made available through the following classes:
447
+ GoogleGeocoder, YahooGeocoder, UsGeocoder, CaGeocoder, and GeonamesGeocoder.
448
+ Further, an additional geocoder class called MultiGeocoder incorporates an ordered failover
449
+ sequence to increase the probability of successful geocoding.
450
+
451
+ All classes are called using the following signature:
452
+
453
+ ```ruby
454
+ include Geokit::Geocoders
455
+ location = XxxGeocoder.geocode(address)
456
+ ```
457
+
458
+ where you replace Xxx Geocoder with the appropriate class. A GeoLoc
459
+ instance is the result of the call. This class has a "success"
460
+ attribute which will be true if a successful geocoding occurred.
461
+ If successful, the lat and lng properties will be populated.
462
+
463
+ Geocoders are named with the convention NameGeocoder. This
464
+ naming convention enables Geocoder to auto-detect its sub-classes
465
+ in order to create methods called `name_geocoder(address)` so that
466
+ all geocoders can be called through the base class. This is done
467
+ purely for convenience; the individual geocoder classes are expected
468
+ to be used independently.
469
+
470
+ The MultiGeocoder class requires the configuration of a provider
471
+ order which dictates what order to use the various geocoders. Ordering
472
+ is done through `Geokit::Geocoders::provider_order`, found in
473
+ `config/initializers/geokit_config.rb`.
474
+
475
+ If you don't already have a `geokit_config.rb` file, the plugin creates one
476
+ when it is first installed.
477
+
478
+ Make sure your failover configuration matches the usage characteristics
479
+ of your application -- for example, if you routinely get bogus input to
480
+ geocode, your code will be much slower if you have to failover among
481
+ multiple geocoders before determining that the input was in fact bogus.
482
+
483
+ The Geocoder.geocode method returns a GeoLoc object. Basic usage:
484
+
485
+ ```ruby
486
+ loc=Geocoder.geocode('100 Spear St, San Francisco, CA')
487
+ if loc.success
488
+ puts loc.lat
489
+ puts loc.lng
490
+ puts loc.full_address
491
+ end
492
+ ```
493
+
494
+ ## REVERSE GEOCODING
495
+
496
+ Currently, only the Google Geocoder supports reverse geocoding.
497
+ Pass the lat/lng as a string, array or LatLng instance:
498
+
499
+ ```ruby
500
+ res=Geokit::Geocoders::GoogleGeocoder.reverse_geocode "37.791821,-122.394679"
501
+ => #<Geokit::GeoLoc:0x558ed0 ...
502
+ res.full_address "101-115 Main St, San Francisco, CA 94105, USA"
503
+ ```
504
+
505
+ The address will usually appear as a range, as it does in the above example.
506
+
507
+
508
+ ## INTEGRATED FIND WITH ADDRESS GEOCODING
509
+
510
+ Just has you can pass an IP address directly into an ActiveRecord finder
511
+ as the origin, you can also pass a physical address as the origin:
512
+
513
+ ```ruby
514
+ Location.find_closest(:origin => '100 Spear st, San Francisco, CA')
515
+ ```
516
+
517
+ where the physical address would be geocoded to a location and then the
518
+ resulting latitude and longitude coordinates would be used in the
519
+ find.
520
+
521
+ Note that if the address fails to geocode, the find method will raise an
522
+ ActiveRecord::GeocodeError you must be prepared to catch. Alternatively,
523
+ You can geocoder the address beforehand, and pass the resulting lat/lng
524
+ into the finder if successful.
525
+
526
+ ## Auto Geocoding
527
+
528
+ If your geocoding needs are simple, you can tell your model to automatically
529
+ geocode itself on create:
530
+
531
+ ```ruby
532
+ class Store < ActiveRecord::Base
533
+ acts_as_mappable :auto_geocode=>true
534
+ end
535
+ ```
536
+
537
+ It takes two optional params:
538
+
539
+ ```ruby
540
+ class Store < ActiveRecord::Base
541
+ acts_as_mappable :auto_geocode=>{:field=>:address, :error_message=>'Could not geocode address'}
542
+ end
543
+ ```
544
+
545
+ . . . which is equivalent to:
546
+
547
+ ```ruby
548
+ class Store << ActiveRecord::Base
549
+ acts_as_mappable
550
+ before_validation :geocode_address, :on => :create
551
+
552
+ private
553
+ def geocode_address
554
+ geo=Geokit::Geocoders::MultiGeocoder.geocode (address)
555
+ errors.add(:address, "Could not Geocode address") if !geo.success
556
+ self.lat, self.lng = geo.lat,geo.lng if geo.success
557
+ end
558
+ end
559
+ ```
560
+
561
+ If you need any more complicated geocoding behavior for your model, you should roll your own
562
+ `before_validate` callback.
563
+
564
+
565
+ ## Distances, headings, endpoints, and midpoints
566
+
567
+ ```ruby
568
+ distance = home.distance_from(work, :units=>:miles)
569
+ heading = home.heading_to(work) # result is in degrees, 0 is north
570
+ endpoint = home.endpoint(90,2) # two miles due east
571
+ midpoint = home.midpoint_to(work)
572
+ ```
573
+
574
+ ## Cool stuff you can do with bounds
575
+
576
+ ```ruby
577
+ bounds = Bounds.new(sw_point,ne_point)
578
+ bounds.contains?(home)
579
+ puts bounds.center
580
+ ```
581
+
582
+ HOW TO . . .
583
+ =================================================================================
584
+
585
+ A few quick examples to get you started ....
586
+
587
+ ## How to install the Geokit Rails plugin
588
+ (See the very top of this file)
589
+
590
+ ## How to find all stores within a 10-mile radius of a given lat/lng
591
+ 1. ensure your stores table has lat and lng columns with numeric or float
592
+ datatypes to store your latitude/longitude
593
+
594
+ 2. use `acts_as_mappable` on your store model:
595
+ 3.
596
+ ```ruby
597
+ class Store < ActiveRecord::Base
598
+ acts_as_mappable
599
+ ...
600
+ end
601
+ ```
602
+
603
+ 3. finders now have extra capabilities:
604
+
605
+ ```ruby
606
+ Store.find(:all, :origin =>[32.951613,-96.958444], :within=>10)
607
+ ```
608
+
609
+ ## How to geocode an address
610
+
611
+ 1. configure your geocoder key(s) in `config/initializers/geokit_config.rb`
612
+
613
+ 2. also in `geokit_config.rb`, make sure that `Geokit::Geocoders::provider_order` reflects the
614
+ geocoder(s). If you only want to use one geocoder, there should
615
+ be only one symbol in the array. For example:
616
+
617
+ ```ruby
618
+ Geokit::Geocoders::provider_order=[:google]
619
+ ```
620
+
621
+ 3. Test it out in script/console
622
+
623
+ ```ruby
624
+ include Geokit::Geocoders
625
+ res = MultiGeocoder.geocode('100 Spear St, San Francisco, CA')
626
+ puts res.lat
627
+ puts res.lng
628
+ puts res.full_address
629
+ ```
630
+
631
+ ... etc. The return type is GeoLoc, see the API for
632
+ all the methods you can call on it.
633
+
634
+ ## How to find all stores within 10 miles of a given address
635
+
636
+ 1. as above, ensure your table has the lat/lng columns, and you've
637
+ applied `acts_as_mappable` to the Store model.
638
+
639
+ 2. configure and test out your geocoder, as above
640
+
641
+ 3. pass the address in under the :origin key
642
+
643
+ ```ruby
644
+ Store.find(:all, :origin=>'100 Spear st, San Francisco, CA', :within=>10)
645
+ ```
646
+
647
+ 4. you can also use a zipcode, or anything else that's geocodable:
648
+
649
+ ```ruby
650
+ Store.find(:all, :origin=>'94117', :conditions=>'distance<10')
651
+ ```
652
+
653
+ ## How to sort a query by distance from an origin
654
+
655
+ You now have access to a 'distance' column, and you can use it
656
+ as you would any other column. For example:
657
+
658
+ ```ruby
659
+ Store.find(:all, :origin=>'94117', :order=>'distance')
660
+ ```
661
+
662
+ ## How to sort elements of an array according to distance from a common point
663
+
664
+ Usually, you can do your sorting in the database as part of your find call.
665
+ If you need to sort things post-query, you can do so:
666
+
667
+ ```ruby
668
+ stores = Store.all
669
+ stores.sort_by{|s| s.distance_to(home)}
670
+ ```
671
+
672
+ Obviously, each of the items in the array must have a latitude/longitude so
673
+ they can be sorted by distance.
674
+
675
+ ## Database indexes
676
+
677
+ MySQL can't create indexes on a calculated field such as those Geokit uses to
678
+ calculate distance based on latitude/longitude values for a record. However,
679
+ indexing the lat and lng columns does improve Geokit distance calculation
680
+ performance since the lat and lng columns are used in a straight comparison
681
+ for distance calculation. Assuming a Page model that is incorporating the
682
+ Geokit plugin the migration would be as follows.
683
+
684
+ ```ruby
685
+ class AddIndexToPageLatAndLng < ActiveRecord::Migration
686
+
687
+ def self.up
688
+ add_index :pages, [:lat, :lng]
689
+ end
690
+
691
+ def self.down
692
+ remove_index :pages, [:lat, :lng]
693
+ end
694
+ end
695
+ ```
696
+
697
+ ## Database Compatability
698
+
699
+ * Geokit works with MySQL (tested with version 5.0.41), PostgreSQL (tested with version 8.2.6) and Microsoft SQL Server (tested with 2000).
700
+ * Geokit is known to *not* work with Postgres versions under 8.1 -- it uses the least() function.
701
+
702
+
703
+ ## HIGH-LEVEL NOTES ON WHAT'S WHERE
704
+
705
+ `acts_as_mappable.rb`, as you'd expect, contains the ActsAsMappable
706
+ module which gets mixed into your models to provide the
707
+ location-based finder goodness.
708
+
709
+ `ip_geocode_lookup.rb` contains the before_action helper method which
710
+ enables auto lookup of the requesting IP address.
711
+
712
+ ### The Geokit gem provides the building blocks of distance-based operations:
713
+
714
+ The Mappable module, which provides basic
715
+ distance calculation methods, i.e., calculating the distance
716
+ between two points.
717
+
718
+ The LatLng class is a simple container for latitude and longitude, but
719
+ it's made more powerful by mixing in the above-mentioned Mappable
720
+ module -- therefore, you can calculate easily the distance between two
721
+ LatLng objects with `distance = first.distance_to(other)`
722
+
723
+ GeoLoc represents an address or location which
724
+ has been geocoded. You can get the city, zipcode, street address, etc.
725
+ from a GeoLoc object. GeoLoc extends LatLng, so you also get lat/lng
726
+ AND the Mappable module goodness for free.