我正在编写一个应用程序,我正在尝试集成一些通用的地理位置功能,包括将一些纬度/纬度坐标保存为数据库中的点。这样做的目的是允许用户使用他们的位置(由设备提供)或谷歌地图标记来选择他们的坐标。我已经成功地从地图或设备中获取坐标,但是我现在无法从它们创建一个点以保存到数据库中。
我已经阅读了文档并尝试将此代码添加到我的初始值设定项中:
初始值设定项/rgeo.rb
require 'rgeo-activerecord'
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
宝石文件:
gem 'activerecord-postgis-adapter'
gem 'rgeo'
gem 'rgeo-activerecord'
迁移:
def change
add_column :monuments, :grid_ref, :point, geographic: true
end
尝试创建点时,我在 rails 控制台中收到此错误:
irb(main):004:0> m.grid_ref = "POINT(-122.193963 47.675086)"
ArgumentError: invalid value for Float(): "POINT(-122.193963 47.675086)"
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql/oid/point.rb:20:in `Float'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql/oid/point.rb:20:in `block in type_cast'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql/oid/point.rb:20:in `map'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql/oid/point.rb:20:in `type_cast'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql/oid/point.rb:18:in `type_cast'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/type/value.rb:23:in `type_cast_from_database'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/type/mutable.rb:5:in `type_cast_from_user'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/attribute.rb:100:in `type_cast'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/attribute.rb:42:in `original_value'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/attribute.rb:37:in `value'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/attribute.rb:46:in `value_for_database'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/attribute_methods/dirty.rb:164:in `store_original_raw_attribute'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/attribute_methods/dirty.rb:93:in `write_attribute'
from /usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/attribute_methods.rb:50:in `__temp__76279646f5275666'
from (irb):4
from /usr/local/lib/ruby/gems/2.2.0/gems/railties-4.2.0/lib/rails/commands/console.rb:110:in `start'
... 9 levels...
from /usr/local/lib/ruby/gems/2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
from /usr/local/lib/ruby/gems/2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `block in load'
from /usr/local/lib/ruby/gems/2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:240:in `load_dependency'
from /usr/local/lib/ruby/gems/2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
from /usr/local/lib/ruby/gems/2.2.0/gems/spring-1.6.4/lib/spring/commands/rails.rb:6:in `call'
from /usr/local/lib/ruby/gems/2.2.0/gems/spring-1.6.4/lib/spring/command_wrapper.rb:38:in `call'
from /usr/local/lib/ruby/gems/2.2.0/gems/spring-1.6.4/lib/spring/application.rb:185:in `block in serve'
from /usr/local/lib/ruby/gems/2.2.0/gems/spring-1.6.4/lib/spring/application.rb:156:in `fork'
from /usr/local/lib/ruby/gems/2.2.0/gems/spring-1.6.4/lib/spring/application.rb:156:in `serve'
from /usr/local/lib/ruby/gems/2.2.0/gems/spring-1.6.4/lib/spring/application.rb:131:in `block in run'
from /usr/local/lib/ruby/gems/2.2.0/gems/spring-1.6.4/lib/spring/application.rb:125:in `loop'
from /usr/local/lib/ruby/gems/2.2.0/gems/spring-1.6.4/lib/spring/application.rb:125:in `run'
from /usr/local/lib/ruby/gems/2.2.0/gems/spring-1.6.4/lib/spring/application/boot.rb:18:in `<top (required)>'
from /usr/local/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /usr/local/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:55:in `require'
在阅读此演示后,我采用了这种方法,这表明该模型隐式理解 WKT 字符串,并在内部将其转换为"点"对象。
找到了解决方案。 必须指定 SRID,geographic_factory现在已spherical_factory,并且点是在指定 SRID 的球形工厂上调用的方法。
目前,我已经实现了以下辅助方法,它适用于rails 4.2.6,postgis和postgresql。
请注意,工厂首先采用经度参数:)
def set_latlon(lat, lng)
factory = RGeo::Geographic.spherical_factory(srid: 4326)
# NOTE: this method takes the LNG parameter first!
self.latlon = factory.point(lng, lat)
end
继续前进,如果您遵循与我相同的空间配置教程,您会注意到以这种方式创建的行将失败。 我通过将:point
列替换为:geographic
列来解决此问题。 迁移代码如下。
class Location < ActiveRecord::Migration
def change
remove_column :locations, :latlon # formerly of type :point
add_column :locations, :latlon, :geography, limit: {:srid=>4326, :type=>"point", :geographic=>true}, null: false
end
end
使用 st_point
,而不是 point
作为类型:
add_column :monuments, :grid_ref, :st_point, geographic: true
Postgresql 添加了point
类型,因此 postgis 适配器中的类型名称更改为 st_point
。
请参阅 https://github.com/rgeo/activerecord-postgis-adapter#point-and-polygon-types-with-activerecord-42:
在版本 3 之前,支持点和面类型。在 ActiveRecord 4.2,Postgresql 适配器增加了对本机的支持 Postgresql 点和多边形类型,与此适配器的冲突 同名的类型。PostGIS 点类型必须引用为 st_point,并且 PostGIS 面类型必须引用为 st_polygon。