The next-generation PostGIS adapter for Rails - clean, modern, and built for the future.
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.
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
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
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
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
)
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
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
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 equalassert_within_distance(point1, point2, distance)
- Assert points within distanceassert_contains(container, contained)
- Assert geometry contains anotherassert_within(inner, outer)
- Assert geometry is within anotherassert_intersects(geom1, geom2)
- Assert geometries intersectassert_disjoint(geom1, geom2)
- Assert geometries don't intersect
Chainable Spatial Column Assertions:
assert_spatial_column(geometry).has_z
- Assert has Z dimensionassert_spatial_column(geometry).has_m
- Assert has M dimensionassert_spatial_column(geometry).has_srid(srid)
- Assert SRID valueassert_spatial_column(geometry).is_type(type)
- Assert geometry typeassert_spatial_column(geometry).is_geographic
- Assert geographic factoryassert_spatial_column(geometry).is_cartesian
- Assert cartesian factory
Geometry Factories:
create_point(x, y, srid: 4326)
- Create test pointscreate_test_polygon(srid: 4326)
- Create test polygonscreate_test_linestring(srid: 4326)
- Create test linestringsfactory(srid: 4326, geographic: false)
- Get geometry factorygeographic_factory(srid: 4326)
- Get geographic factorycartesian_factory(srid: 0)
- Get cartesian factory
🌍 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
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.
Bug reports and pull requests are welcome on GitHub at https://github.com/seuros/activerecord-postgis.
The gem is available as open source under the terms of the MIT License.