PostGIS: Save a point with z coordinate to an existing ActiveRecord model

By Ryan Romanchuk
On

Prerequisite and Assumptions

  • PostGIS[1] configured
  • activerecord-postgis-adapter[2] gem installed
# db/migration/add_location_column_to_pireps.rb
class AddLocationColumnToPireps < ActiveRecord::Migration[7.0]
  def change
    add_column :wx_pireps, :location, :st_point, geographic: true, has_z: true
    add_index : wx_pireps, :location, using: :gist
  end
end

# app/models/wx/pirep.rb
module Wx
  class Pirep < ApplicationRecord
  end
end

# config/initializers/rgeo_factories.rb
RGeo::ActiveRecord::SpatialFactoryStore.instance.tap do |store|
  store.default = RGeo::Cartesian.preferred_factory

  store.register(RGeo::Geographic.spherical_factory(srid: 4326, has_z_coordinate: true),
                 { geo_type: 'point', srid: 4326, sql_type: 'geography' })
end
Usage
# Factory
pirep = Wx::Pirep.new
factory = pirep.location.factory
pirep.location = factory.point(-120.0, 43.0, 4500.0)
pirep.save!

# String literal via 'POINT( LON LAT Z)'
Wx::Pirep.create!(location: 'POINT(-129.0 43.0 4500.0)')

# Global 
RGeo::Geographic.spherical_factory(srid: 4326, has_z_coordinate: true).point(longitude, latitude,
                                                                                                   altitude_ft_msl).to_s
# => 'POINT(-129.0 43.0 4500.0)'

pirep.location.z
# => 4500.0

  1. https://postgis.net ↩︎

  2. https://github.com/rgeo/activerecord-postgis-adapter ↩︎

talk