ActiveRecord::PostGIS
The next-generation PostGIS adapter for Rails - clean, modern, and built for the future.
Why This Gem?
This is the next-generation PostGIS adapter that brings PostGIS support to Rails the right way:
✅ Use standard postgres://
URLs - No custom adapter names, no special configuration
✅ No monkey patching - Clean extensions using Rails 8 patterns
✅ No obscure hacks - Transparent, well-documented implementation
✅ Latest APIs - Built for Rails 8+ and Ruby 3.3+
✅ Zero configuration - Just add the gem and it works
Unlike legacy PostGIS adapters that require custom database URLs, special configurations, and complex setup, this gem extends the existing PostgreSQL adapter seamlessly. Your database configuration stays clean and standard.
Installation
Add this line to your application's Gemfile:
gem 'activerecord-postgis'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install activerecord-postgis
Configuration
Zero configuration required! Just use your standard PostgreSQL database configuration:
# config/database.yml
development:
adapter: postgresql
url: postgres://user:password@localhost/myapp_development
# That's it! No special adapter, no custom configuration
Usage
Migrations
Create spatial columns using PostGIS types:
class CreateLocations < ActiveRecord::Migration[8.0]
def change
create_table :locations do |t|
t.st_point :coordinates, srid: 4326
t.st_polygon :boundary, geographic: true
t.st_line_string :route, has_z: true
t.timestamps
end
end
end
Spatial Queries
With RGeo Objects (Recommended):
# Create RGeo geometries
factory = RGeo::Geographic.spherical_factory(srid: 4326)
point = factory.point(-5.923647, 35.790897) # Cap Spartel, Tangier, Morocco
polygon = factory.polygon(...)
# Direct queries with RGeo objects
Location.where(coordinates: point)
Location.where("ST_Distance(coordinates, ?) < ?", point, 1000)
# Using parameterized queries (automatically quoted)
locations_nearby = Location.where(
"ST_DWithin(coordinates, ?, ?)",
point,
1000 # meters
)
# Complex spatial queries
parks_in_city = Park.where(
"ST_Within(boundary, ?)",
city_polygon
)
With Arel Spatial Methods:
# Find locations within distance
Location.where(
Location.arel_table[:coordinates].st_distance(point).lt(1000)
)
# Find polygons that contain a point
Boundary.where(
Boundary.arel_table[:area].st_contains(Arel.spatial(point))
)
# Calculate lengths and areas
Route.select(
Route.arel_table[:path].st_length.as('distance')
)
With WKT Strings:
# Using Well-Known Text format
Location.where(
"ST_Distance(coordinates, ST_GeomFromText(?)) < ?",
"POINT(-5.923647 35.790897)",
1000
)
Model Integration
class Location < ApplicationRecord
# Works automatically - no configuration needed
# Spatial attributes are automatically parsed and serialized
end
location = Location.create!(
coordinates: "POINT(-5.923647 35.790897)" # Tangier, Morocco
)
puts location.coordinates.x # -5.923647
puts location.coordinates.y # 35.790897
Testing
When testing spatial functionality in your Rails application, this gem provides helpful test utilities:
# In your test_helper.rb or rails_helper.rb
require 'activerecord-postgis/test_helper'
class ActiveSupport::TestCase
include ActiveRecordPostgis::TestHelper
end
# Or for RSpec
RSpec.configure do |config|
config.include ActiveRecordPostgis::TestHelper
end
Test Helper Methods
class LocationTest < ActiveSupport::TestCase
def test_spatial_operations
# Create test geometries
point1 = create_point(-5.9, 35.8)
point2 = create_point(-5.91, 35.81)
polygon = create_test_polygon
location = Location.create!(coordinates: point1, boundary: polygon)
# Traditional assertions
assert_spatial_equal point1, location.coordinates
assert_within_distance point1, point2, 200 # meters
assert_contains polygon, point1
# New chainable syntax (recommended)
assert_spatial_column(location.coordinates)
.has_srid(4326)
.is_type(:point)
.is_geographic
assert_spatial_column(location.boundary)
.is_type(:polygon)
.has_srid(4326)
end
def test_3d_geometry
point_3d = create_point(1.0, 2.0, srid: 4326, z: 10.0)
assert_spatial_column(point_3d)
.has_z
.has_srid(4326)
.is_type(:point)
.is_cartesian
end
end
Available Test Helpers:
Traditional Assertions:
-
assert_spatial_equal(expected, actual)
- Assert spatial objects are equal -
assert_within_distance(point1, point2, distance)
- Assert points within distance -
assert_contains(container, contained)
- Assert geometry contains another -
assert_within(inner, outer)
- Assert geometry is within another -
assert_intersects(geom1, geom2)
- Assert geometries intersect -
assert_disjoint(geom1, geom2)
- Assert geometries don't intersect
Chainable Spatial Column Assertions:
-
assert_spatial_column(geometry).has_z
- Assert has Z dimension -
assert_spatial_column(geometry).has_m
- Assert has M dimension -
assert_spatial_column(geometry).has_srid(srid)
- Assert SRID value -
assert_spatial_column(geometry).is_type(type)
- Assert geometry type -
assert_spatial_column(geometry).is_geographic
- Assert geographic factory -
assert_spatial_column(geometry).is_cartesian
- Assert cartesian factory
Geometry Factories:
-
create_point(x, y, srid: 4326)
- Create test points -
create_test_polygon(srid: 4326)
- Create test polygons -
create_test_linestring(srid: 4326)
- Create test linestrings -
factory(srid: 4326, geographic: false)
- Get geometry factory -
geographic_factory(srid: 4326)
- Get geographic factory -
cartesian_factory(srid: 0)
- Get cartesian factory
Features
🌍 Complete PostGIS Type Support
-
st_point
,st_line_string
,st_polygon
-
st_multi_point
,st_multi_line_string
,st_multi_polygon
-
st_geometry_collection
,st_geography
- Support for SRID, Z/M dimensions
🔍 Spatial Query Methods
-
st_distance
,st_contains
,st_within
,st_length
- Custom Arel visitor for PostGIS SQL generation
- Seamless integration with ActiveRecord queries
⚡ Modern Architecture
- Built on Rails 8 patterns
- Clean module extensions (no inheritance)
- Proper type registration and schema dumping
- Compatible with multi-database setups
🛠️ Developer Experience
- Standard
postgres://
URLs - Works with existing PostgreSQL tools
- Clear error messages and debugging
- Full RGeo integration
- Comprehensive test helpers for spatial assertions
Acknowledgments
This gem builds upon the incredible work of many contributors to the Ruby geospatial ecosystem:
🙏 RGeo Ecosystem - The foundation that makes Ruby geospatial possible:
- RGeo originally by Daniel Azuma, currently maintained by Keith Doggett (@keithdoggett) and Ulysse Buonomo (@BuonOmo)
- RGeo::ActiveRecord for ActiveRecord integration
- RGeo::Proj4 for coordinate system transformations
- Former maintainer Tee Parham and all contributors who built this ecosystem
🗺️ PostGIS Pioneers - Previous PostGIS adapters that paved the way:
- activerecord-postgis-adapter by Daniel Azuma and the RGeo team
- All the maintainers and contributors who solved spatial data challenges in Rails
🌍 PostGIS & GEOS - The underlying spatial powerhouses:
- PostGIS developers for the amazing spatial database extension
- GEOS contributors for computational geometry
- PostgreSQL team for the solid foundation
This gem exists because of their pioneering work. I'm simply bringing it into the modern Rails era with cleaner patterns and zero configuration.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/seuros/activerecord-postgis.
License
The gem is available as open source under the terms of the MIT License.