Reputation: 896
there is a typical schema when Address
model has an RGeo attribute:
t.st_point :coordinates, geographic: true, srid: 4326
and normally it is wrapped in the RGeo::Geographic::SphericalPointImpl
class
Realty.last.address.coordinates
#<RGeo::Geographic::SphericalPointImpl:0x2b1a364b429c "POINT (106.5 10.5)">
but in some situations, it is wrapped with completely inappropriate Cartesian wrapper RGeo::Cartesian::PointImpl
Realty.joins(:address).select('realties.id, addresses.coordinates::geometry').first.coordinates
#<RGeo::Cartesian::PointImpl:0x2b1a364a691c "POINT (106.0 10.0)">
I'm using latest 'activerecord-postgis-adapter 3.1.4'
with rails 4.2.4
Maybe anybody know how a way to fix this, i.e. make coordinates
always return instance of RGeo::Geographic::SphericalPointImpl
?
Upvotes: 2
Views: 1679
Reputation: 4409
When you select the column with addresses.coordinates::geometry
, you are forcing Postgres to return a column of type geometry. When you do Realty.last.address.coordinates
, you are returning a different SQL type (a point).
I would remove the ::geometry
from your SQL query.
From the docs at https://github.com/rgeo/rgeo-activerecord#spatial-factories-for-columns:
activerecord-postgis-adapter
converts the SQL type to a ruby type using the SpatialFactoryStore
class as the registry to lookup types.
Register spatial factories in the SpatialFactoryStore
singleton class. Each spatial type in your ActiveRecord models will use the SpatialFactoryStore
to retrieve a factory matching the properties of its type. For example, you can set a different spatial factory for point types, or for types matching a specific SRID, or having a Z coordinate, or any combination of attributes.
The supported keys when registering a spatial type are listed here with their default values and other allowed values:
geo_type: "geometry", # point, polygon, line_string, geometry_collection,
# multi_line_string, multi_point, multi_polygon
has_m: false, # true
has_z: false, # true
sql_type: "geometry", # geography
srid: 0, # (any valid SRID)
The default factories are RGeo::Geographic.spherical_factory
for geographic types, and RGeo::Cartesian.preferred_factory
for geometric types.
Here is an example setup:
RGeo::ActiveRecord::SpatialFactoryStore.instance.tap do |config|
# By default, use the GEOS implementation for spatial columns.
config.default = RGeo::Geos.factory_generator
# But use a geographic implementation for point columns.
config.register(RGeo::Geographic.spherical_factory(srid: 4326), geo_type: "point")
end
Upvotes: 2