has_geo_lookup 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 556e93ddd252169fbee37ee0bfcb91c43ec80815c66db3dcafa0ff3d47cfe56e
4
+ data.tar.gz: a49a34d5cf6f0ab901a18203a9da65be64f7f65faec1e54a4d4d9d7bdb102f40
5
+ SHA512:
6
+ metadata.gz: 446d6d3e34e04ba14f418ef6d3ce62d7dc4a8045931ad6d3a9f2b12b8b315f996d2a6eeb279b43da40c4881fd5914ed194c7ff34e927f1b03425e790dc236ad0
7
+ data.tar.gz: 1bc6c467f8d9e3b592a8522dae18013d11e7d2ea6ea93001972fc528ebcddc3a423b62bff07d36b7ab122dfd0127bfe7b257f0c0f69a5eba4584355160a049a8
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2025-08-18
4
+
5
+ - Initial release
@@ -0,0 +1,132 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ * Demonstrating empathy and kindness toward other people
21
+ * Being respectful of differing opinions, viewpoints, and experiences
22
+ * Giving and gracefully accepting constructive feedback
23
+ * Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ * Focusing on what is best not just for us as individuals, but for the overall
26
+ community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ * The use of sexualized language or imagery, and sexual attention or advances of
31
+ any kind
32
+ * Trolling, insulting or derogatory comments, and personal or political attacks
33
+ * Public or private harassment
34
+ * Publishing others' private information, such as a physical or email address,
35
+ without their explicit permission
36
+ * Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official email address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ [INSERT CONTACT METHOD].
64
+ All complaints will be reviewed and investigated promptly and fairly.
65
+
66
+ All community leaders are obligated to respect the privacy and security of the
67
+ reporter of any incident.
68
+
69
+ ## Enforcement Guidelines
70
+
71
+ Community leaders will follow these Community Impact Guidelines in determining
72
+ the consequences for any action they deem in violation of this Code of Conduct:
73
+
74
+ ### 1. Correction
75
+
76
+ **Community Impact**: Use of inappropriate language or other behavior deemed
77
+ unprofessional or unwelcome in the community.
78
+
79
+ **Consequence**: A private, written warning from community leaders, providing
80
+ clarity around the nature of the violation and an explanation of why the
81
+ behavior was inappropriate. A public apology may be requested.
82
+
83
+ ### 2. Warning
84
+
85
+ **Community Impact**: A violation through a single incident or series of
86
+ actions.
87
+
88
+ **Consequence**: A warning with consequences for continued behavior. No
89
+ interaction with the people involved, including unsolicited interaction with
90
+ those enforcing the Code of Conduct, for a specified period of time. This
91
+ includes avoiding interactions in community spaces as well as external channels
92
+ like social media. Violating these terms may lead to a temporary or permanent
93
+ ban.
94
+
95
+ ### 3. Temporary Ban
96
+
97
+ **Community Impact**: A serious violation of community standards, including
98
+ sustained inappropriate behavior.
99
+
100
+ **Consequence**: A temporary ban from any sort of interaction or public
101
+ communication with the community for a specified period of time. No public or
102
+ private interaction with the people involved, including unsolicited interaction
103
+ with those enforcing the Code of Conduct, is allowed during this period.
104
+ Violating these terms may lead to a permanent ban.
105
+
106
+ ### 4. Permanent Ban
107
+
108
+ **Community Impact**: Demonstrating a pattern of violation of community
109
+ standards, including sustained inappropriate behavior, harassment of an
110
+ individual, or aggression toward or disparagement of classes of individuals.
111
+
112
+ **Consequence**: A permanent ban from any sort of public interaction within the
113
+ community.
114
+
115
+ ## Attribution
116
+
117
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
+ version 2.1, available at
119
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120
+
121
+ Community Impact Guidelines were inspired by
122
+ [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123
+
124
+ For answers to common questions about this code of conduct, see the FAQ at
125
+ [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126
+ [https://www.contributor-covenant.org/translations][translations].
127
+
128
+ [homepage]: https://www.contributor-covenant.org
129
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130
+ [Mozilla CoC]: https://github.com/mozilla/diversity
131
+ [FAQ]: https://www.contributor-covenant.org/faq
132
+ [translations]: https://www.contributor-covenant.org/translations
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Michael Edlund
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,389 @@
1
+ # HasGeoLookup
2
+
3
+ Rails gem for geographic lookup functionality using GeoBoundaries.org and Geonames.org datasets. Provides coordinate validation with automatic radian/degree detection, spatial containment queries, distance-based lookups, and metropolitan area support.
4
+
5
+ ## Features
6
+
7
+ - **Coordinate Validation** - Automatically detect and convert between radians and degrees using country boundary validation
8
+ - **Spatial Queries** - PostGIS-optimized boundary containment with graceful fallback for other databases
9
+ - **Distance-Based Lookup** - Find nearest geographic features within specified radius
10
+ - **Administrative Boundaries** - Query points against ADM1-ADM4 level boundaries from GeoBoundaries.org
11
+ - **Metro Area Support** - Define custom metropolitan areas as collections of administrative boundaries
12
+ - **Multi-Source Comparison** - Compare geographic data across different sources with extensible hooks
13
+ - **Data Coverage Analysis** - Utilities for analyzing geographic data completeness
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'has_geo_lookup'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ ```bash
26
+ bundle install
27
+ ```
28
+
29
+ ## Setup
30
+
31
+ ### 1. Generate Database Migrations
32
+
33
+ ```bash
34
+ rails generate has_geo_lookup:install
35
+ ```
36
+
37
+ This creates migrations for all required tables:
38
+ - `geonames` - Geographic place data from Geonames.org
39
+ - `geoboundaries` - Administrative boundaries from GeoBoundaries.org
40
+ - `feature_codes` - Classification codes for geographic features
41
+ - `metros` - Metropolitan area definitions
42
+ - `metros_geoboundaries` - Join table for metro-boundary associations
43
+
44
+ ### 2. Run Migrations
45
+
46
+ ```bash
47
+ rails db:migrate
48
+ ```
49
+
50
+ ### 3. Import Geographic Data
51
+
52
+ Import geoboundaries and geonames for specific countries:
53
+
54
+ ```bash
55
+ # Import both datasets for United States (recommended)
56
+ rails geo:import[US]
57
+
58
+ # Import for multiple countries
59
+ rails geo:import[CA] # Canada
60
+ rails geo:import[GB] # United Kingdom
61
+
62
+ # Or import datasets separately
63
+ rails geoboundaries:import[US] # Administrative boundaries only
64
+ rails geonames:import[US] # Geographic place names only
65
+ ```
66
+
67
+ ### 4. Include in Your Models
68
+
69
+ Add the concern to any model with `latitude` and `longitude` attributes:
70
+
71
+ ```ruby
72
+ class Listing < ApplicationRecord
73
+ include HasGeoLookup
74
+
75
+ # Your model must have these attributes:
76
+ # - latitude (decimal)
77
+ # - longitude (decimal)
78
+ end
79
+ ```
80
+
81
+ ## Database Requirements
82
+
83
+ ### MySQL 8.0+ with Spatial Extensions (Recommended)
84
+
85
+ The gem works well with MySQL 8.0+ spatial support:
86
+
87
+ ```ruby
88
+ # Gemfile
89
+ gem 'mysql2'
90
+ ```
91
+
92
+ MySQL 8.0+ provides:
93
+ - GEOMETRY column type for storing boundary polygons
94
+ - ST_Contains, ST_GeomFromText, and other spatial functions
95
+ - Coordinate validation using actual country boundaries
96
+ - Spatial indexing for performance
97
+
98
+ ### PostgreSQL with PostGIS (Also Supported)
99
+
100
+ For PostgreSQL databases with PostGIS:
101
+
102
+ ```ruby
103
+ # Gemfile
104
+ gem 'activerecord-postgis-adapter'
105
+ ```
106
+
107
+ PostGIS provides enhanced spatial capabilities and may offer better performance for complex spatial operations.
108
+
109
+ ### Other Databases
110
+
111
+ For SQLite and databases without spatial extensions:
112
+ - Spatial queries will be limited but functional
113
+ - Coordinate validation uses fallback detection methods
114
+ - Basic geographic lookup functionality remains available
115
+
116
+ ## Usage
117
+
118
+ ### Basic Geographic Lookup
119
+
120
+ ```ruby
121
+ listing = Listing.find(123)
122
+
123
+ # Find nearest populated places within 50km
124
+ places = listing.nearest_geonames(
125
+ feature_code: "PPL", # Populated place
126
+ radius_km: 50,
127
+ limit: 10
128
+ )
129
+
130
+ # Find containing administrative boundaries
131
+ boundaries = listing.containing_geoboundaries(level: "ADM2") # Counties
132
+
133
+ # Get geographic summary
134
+ summary = listing.compare_geo_sources
135
+ puts summary
136
+ ```
137
+
138
+ ### Coordinate Validation
139
+
140
+ The gem automatically handles coordinate format detection:
141
+
142
+ ```ruby
143
+ # These coordinates could be in radians or degrees
144
+ lat, lng = 0.768131687, 0.077125907 # Uzès, France in radians
145
+
146
+ # Automatically detects format and converts to degrees
147
+ validated_lat, validated_lng = listing.validate_and_convert_coordinates(lat, lng, "FR")
148
+ # => [44.011, 4.419] (converted to degrees)
149
+
150
+ # Already in degrees - no conversion needed
151
+ validated_lat, validated_lng = listing.validate_and_convert_coordinates(44.011, 4.419, "FR")
152
+ # => [44.011, 4.419] (unchanged)
153
+ ```
154
+
155
+ ### Metro Area Support
156
+
157
+ Define custom metropolitan areas:
158
+
159
+ ```ruby
160
+ # Create a metro area
161
+ bay_area = Metro.create!(
162
+ name: "San Francisco Bay Area",
163
+ country_code: "US",
164
+ population: 7_750_000
165
+ )
166
+
167
+ # Associate with counties (geoboundaries)
168
+ sf_county = Geoboundary.find_by(name: "San Francisco County")
169
+ alameda_county = Geoboundary.find_by(name: "Alameda County")
170
+ bay_area.geoboundaries << [sf_county, alameda_county]
171
+
172
+ # Check if coordinates are in metro area
173
+ bay_area.contains_point?(37.7749, -122.4194) # => true
174
+
175
+ # Get metro area statistics
176
+ bay_area.total_area_km2 # => 18040.5
177
+ bay_area.population_density # => 429.8
178
+ bay_area.boundary_names # => ["San Francisco County", "Alameda County", ...]
179
+ ```
180
+
181
+ ### Data Coverage Analysis
182
+
183
+ ```ruby
184
+ # Analyze data completeness
185
+ coverage = HasGeoLookup::DataCoverage.coverage_status("US")
186
+ puts coverage[:geonames_count] # Number of geonames records
187
+ puts coverage[:boundaries_count] # Number of boundary records
188
+ puts coverage[:feature_coverage] # Coverage by feature type
189
+
190
+ # Check if specific data exists
191
+ HasGeoLookup::DataCoverage.has_boundary_data?("US", "ADM2") # => true
192
+ HasGeoLookup::DataCoverage.has_geonames_data?("US") # => true
193
+ ```
194
+
195
+ ### Advanced Usage
196
+
197
+ #### Custom Source Comparison
198
+
199
+ Extend geographic comparison for your specific data sources:
200
+
201
+ ```ruby
202
+ class Listing < ApplicationRecord
203
+ include HasGeoLookup
204
+
205
+ # Define additional data sources for comparison
206
+ def additional_source_columns
207
+ ['api_latitude', 'api_longitude', 'geocoded_lat', 'geocoded_lng']
208
+ end
209
+
210
+ def additional_source_legend
211
+ {
212
+ 'API' => 'Third-party API data',
213
+ 'Geocoded' => 'Address-based geocoding'
214
+ }
215
+ end
216
+
217
+ def get_source_value(column_name)
218
+ case column_name
219
+ when 'api_latitude', 'api_longitude'
220
+ # Custom logic to fetch from your API
221
+ when 'geocoded_lat', 'geocoded_lng'
222
+ # Custom logic for geocoded coordinates
223
+ end
224
+ end
225
+ end
226
+ ```
227
+
228
+ #### Distance Calculations
229
+
230
+ ```ruby
231
+ # Find records within radius using database query
232
+ nearby_listings = Listing.joins(:nearest_geonames)
233
+ .where("geonames.feature_code = 'PPL'")
234
+ .where(geonames: { country_code: "US" })
235
+
236
+ # Calculate distance between two points
237
+ distance_km = listing.distance_to_point(40.7128, -74.0060)
238
+ ```
239
+
240
+ ## Configuration
241
+
242
+ ### Rails Generators
243
+
244
+ Customize migration generation:
245
+
246
+ ```ruby
247
+ # config/application.rb
248
+ config.generators do |g|
249
+ g.has_geo_lookup_skip_migrations = false # Set to true to skip auto-generation
250
+ end
251
+ ```
252
+
253
+ ### PostGIS Configuration
254
+
255
+ For PostGIS databases, ensure the extension is enabled:
256
+
257
+ ```ruby
258
+ # In a migration or database setup
259
+ enable_extension 'postgis'
260
+ ```
261
+
262
+ ## Data Sources
263
+
264
+ This gem integrates data from:
265
+
266
+ - **[GeoBoundaries.org](https://www.geoboundaries.org/)** - Administrative boundary polygons (ADM1-ADM4 levels)
267
+ - **[Geonames.org](http://www.geonames.org/)** - Geographic place names and coordinates
268
+ - **[ISO 3166](https://en.wikipedia.org/wiki/ISO_3166)** - Country code validation
269
+
270
+ ## Performance Considerations
271
+
272
+ ### Database Setup and Optimization
273
+
274
+ The gem includes built-in tools to analyze and set up the complete database requirements for HasGeoLookup functionality:
275
+
276
+ ```bash
277
+ # Check HasGeoLookup setup for all models (columns and indexes)
278
+ rake has_geo_lookup:check_setup
279
+
280
+ # Preview what setup changes would be made (dry run)
281
+ rake has_geo_lookup:preview_setup
282
+
283
+ # Generate Rails migration for complete HasGeoLookup setup
284
+ rake has_geo_lookup:create_setup
285
+
286
+ # Analyze a specific model in detail
287
+ rake has_geo_lookup:analyze_model[Listing]
288
+ ```
289
+
290
+ **Programmatic Setup Management:**
291
+
292
+ ```ruby
293
+ # Get performance analysis for all models
294
+ results = HasGeoLookup::IndexChecker.analyze_all_models
295
+
296
+ # Check a specific model
297
+ analysis = HasGeoLookup::IndexChecker.check_model(Listing)
298
+ puts "Missing indexes: #{analysis[:missing_indexes]}"
299
+ puts "Recommendations: #{analysis[:recommendations]}"
300
+
301
+ # Generate migration file for missing columns and indexes
302
+ migration_path = HasGeoLookup::IndexChecker.generate_index_migration
303
+ # Or for a specific model:
304
+ migration_path = HasGeoLookup::IndexChecker.generate_index_migration(Listing)
305
+
306
+ # Generate a comprehensive performance report
307
+ puts HasGeoLookup::IndexChecker.performance_report
308
+ ```
309
+
310
+ **Complete Database Setup:**
311
+
312
+ The `create_setup` task generates proper Rails migration files that can be committed to version control and run as part of your deployment process. The migration includes:
313
+
314
+ - **Required columns**: Adds `latitude` and `longitude` decimal columns if missing
315
+ - **Recommended indexes**: Creates optimized database indexes for geographic queries
316
+ - **Proper rollback**: Includes reversible `down` migration methods
317
+
318
+ This ensures all environments get the same database structure and maintains proper migration history.
319
+
320
+ ### Database Optimization
321
+
322
+ For large datasets:
323
+
324
+ ```ruby
325
+ # Coordinate indexes (essential for spatial queries)
326
+ add_index :your_table, [:latitude, :longitude]
327
+ add_index :your_table, :latitude
328
+ add_index :your_table, :longitude
329
+
330
+ # Geographic attribute indexes (for filtering and joining)
331
+ add_index :your_table, :country
332
+ add_index :your_table, :state_or_province
333
+ add_index :your_table, :city
334
+ add_index :your_table, :postal_code
335
+
336
+ # For geoboundaries and geonames tables
337
+ add_index :geonames, [:country_code, :feature_code]
338
+ add_index :geoboundaries, [:level, :shape_iso]
339
+
340
+ # For PostGIS, spatial indexes are created automatically
341
+ ```
342
+
343
+ ### Query Optimization
344
+
345
+ ```ruby
346
+ # Use specific feature codes to limit results
347
+ places = listing.nearest_geonames(
348
+ feature_code: ["PPL", "PPLA", "PPLA2"], # Cities and towns only
349
+ limit: 5
350
+ )
351
+
352
+ # Specify administrative levels for boundaries
353
+ boundaries = listing.containing_geoboundaries(level: ["ADM1", "ADM2"])
354
+ ```
355
+
356
+ ## Development
357
+
358
+ ### Running Tests
359
+
360
+ ```bash
361
+ cd has_geo_lookup
362
+ bundle install
363
+ ruby -Ilib -Itest test/has_geo_lookup_test.rb
364
+ ```
365
+
366
+ ### Contributing
367
+
368
+ 1. Fork the repository
369
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
370
+ 3. Add tests for your changes
371
+ 4. Ensure tests pass
372
+ 5. Commit your changes (`git commit -am 'Add amazing feature'`)
373
+ 6. Push to the branch (`git push origin feature/amazing-feature`)
374
+ 7. Create a Pull Request
375
+
376
+ ## License
377
+
378
+ This gem is available as open source under the terms of the MIT License.
379
+
380
+ ## Changelog
381
+
382
+ ### Version 0.1.0
383
+ - Initial release
384
+ - Coordinate validation with radian/degree detection
385
+ - PostGIS spatial queries with fallback support
386
+ - GeoBoundaries and Geonames integration
387
+ - Metro area support
388
+ - Comprehensive test suite
389
+ - Rails generators for easy setup
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create
7
+
8
+ task default: :test
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+ require 'rails/generators/migration'
5
+
6
+ module HasGeoLookup
7
+ module Generators
8
+ # Generates database migrations for HasGeoLookup gem
9
+ #
10
+ # Creates all necessary tables for geographic lookup functionality:
11
+ # - geonames: Geographic place data from Geonames.org
12
+ # - geoboundaries: Administrative boundaries from GeoBoundaries.org
13
+ # - feature_codes: Classification codes for geographic features
14
+ # - metros: Metropolitan area definitions
15
+ # - geoboundaries_metros: Join table for metro-boundary associations
16
+ # - geonames_metros: Join table for geoname-metro associations
17
+ #
18
+ # @example Generate migrations
19
+ # rails generate has_geo_lookup:install
20
+ class InstallGenerator < Rails::Generators::Base
21
+ include Rails::Generators::Migration
22
+
23
+ source_root File.expand_path('templates', __dir__)
24
+
25
+ desc 'Generate HasGeoLookup database migrations'
26
+
27
+ # Provide a migration timestamp
28
+ def self.next_migration_number(dirname)
29
+ next_migration_number = current_migration_number(dirname) + 1
30
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
31
+ end
32
+
33
+ def create_migrations
34
+ migration_template 'create_geonames.rb.erb', 'db/migrate/create_geonames.rb'
35
+ sleep 1 # Ensure different timestamps
36
+ migration_template 'create_geoboundaries.rb.erb', 'db/migrate/create_geoboundaries.rb'
37
+ sleep 1
38
+ migration_template 'create_feature_codes.rb.erb', 'db/migrate/create_feature_codes.rb'
39
+ sleep 1
40
+ migration_template 'create_metros.rb.erb', 'db/migrate/create_metros.rb'
41
+ sleep 1
42
+ migration_template 'create_geoboundaries_metros.rb.erb', 'db/migrate/create_geoboundaries_metros.rb'
43
+ sleep 1
44
+ migration_template 'create_geonames_metros.rb.erb', 'db/migrate/create_geonames_metros.rb'
45
+ end
46
+
47
+ def display_readme
48
+ readme "INSTALL.md"
49
+ end
50
+
51
+ private
52
+
53
+ def migration_version
54
+ if Rails.version.start_with?('8')
55
+ '[8.0]'
56
+ elsif Rails.version.start_with?('7')
57
+ '[7.0]'
58
+ elsif Rails.version.start_with?('6')
59
+ '[6.0]'
60
+ else
61
+ '[5.0]'
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,60 @@
1
+ # HasGeoLookup Installation Complete
2
+
3
+ The HasGeoLookup gem migrations have been generated successfully!
4
+
5
+ ## Next Steps
6
+
7
+ 1. **Run the migrations:**
8
+ ```bash
9
+ bin/rails db:migrate
10
+ ```
11
+
12
+ 2. **For PostGIS users (recommended):**
13
+ - Ensure PostGIS extension is available in your PostgreSQL database
14
+ - The migrations will automatically enable PostGIS and create spatial indexes
15
+ - This provides optimal performance for boundary queries and coordinate validation
16
+
17
+ 3. **For non-PostGIS databases:**
18
+ - The gem will work with MySQL, SQLite, or other databases
19
+ - Spatial queries will be limited, but basic geographic lookup functionality remains available
20
+ - Coordinate validation will use fallback methods instead of boundary containment
21
+
22
+ 4. **Import geographic data:**
23
+ ```bash
24
+ # Import geoboundaries and geonames for a specific country (recommended)
25
+ bin/rails geo:import[US]
26
+
27
+ # Or import datasets separately
28
+ bin/rails geoboundaries:import[US] # Administrative boundaries
29
+ bin/rails geonames:import[US] # Geographic place names
30
+ ```
31
+
32
+ 5. **Include the concern in your models:**
33
+ ```ruby
34
+ class Listing < ApplicationRecord
35
+ include HasGeoLookup
36
+
37
+ # Your model must have latitude and longitude attributes
38
+ # The gem will provide geographic lookup methods
39
+ end
40
+ ```
41
+
42
+ ## Available Tables
43
+
44
+ The following tables have been created:
45
+
46
+ - **`geonames`** - Geographic place data from Geonames.org
47
+ - **`geoboundaries`** - Administrative boundary polygons from GeoBoundaries.org
48
+ - **`feature_codes`** - Classification codes for geographic features
49
+ - **`metros`** - Custom metropolitan area definitions
50
+ - **`metros_geoboundaries`** - Join table linking metros to their constituent boundaries
51
+
52
+ ## Key Features
53
+
54
+ - **Coordinate validation** - Automatically detect and convert between radians/degrees
55
+ - **Boundary containment** - Find which administrative boundaries contain a point
56
+ - **Distance-based lookup** - Find nearest geographic features within a radius
57
+ - **Metro area support** - Group boundaries into custom metropolitan regions
58
+ - **Multi-source comparison** - Compare geographic data across different sources
59
+
60
+ For detailed usage examples and API documentation, see the gem's README.