So I'm trying to get up to speed on location based programming in Rails for a project. In summary, my database data appears to be correct, but I can't get the rails in-memory logic to get correct results.
I have created a lonlat column in my database...
add_column :bars, :lonlat, :st_point, geographic: true
Which has created the appropriate entry in my schema file...
t.geography "lonlat", limit: {:srid=>4326, :type=>"st_point", :geographic=>true}
And when I run queries like Bar.where("ST_Distance(lonlat, 'Point(0,0)') < 10000")
I get back the results that are sane. (I haven't checked accuracy, just rough sanity). For example, if I run Bar.where("ST_Distance(lonlat, 'Point(0,0)') < 100").count
I get back 1 -- the single record that happens to be at the relevant point.
But if I load up the records...
b1 = Bar.first
b2 = Bar.second
b1.lonlat.distance(b2.lonlat)
# Result is around or below 0.009
That result is flat wrong. The two points are, in fact, about 3000 feet apart, and quick examination of the count query above shows that the database, at least, understands this.
So, from what I can tell, the issue is only once I've loaded the points into memory.
As per instructions in a few tutorials / documentaiton for RGeo, I have created an initializer file named geography.rb
with the following contents, under /config/initializers
.
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")
# Also tried the additional calls to try and get the declaration to match my schema file's column definition
config.register(RGeo::Geographic.spherical_factory(srid: 4326), geo_type: "point", geographic: true)
config.register(RGeo::Geographic.spherical_factory(srid: 4326), geo_type: "st_point")
config.register(RGeo::Geographic.spherical_factory(srid: 4326), geo_type: "st_point", geographic: true)
end
My understanding is that this code -- particularly the second call, config.register
, should tell RGeo to treat point data as geographic. Based on this question, I'm guessing I might need to adjust the register call to match my schema file, so I actually have 4 copies of the register line, covering geo_type: "point"/"st_point", and the presence/absence of geographic: true.
Hasn't helped.
What am I missing / misunderstanding / doing wrong? I'm guessing it's a configuration issue, just don't know what it is, and unfortunately I've reached the limit of what I can figure out based on documentations and tutorials that -- alas -- have gone slightly out of date.