RGeo error attempting to create point from lat/lon

為{幸葍}努か 提交于 2019-12-12 14:05:54

问题


I'm writing an app which I am attempting to integrate some general geolocation functionality including saving some lat/lon coordinates as a point in a database. The intention of this is to allow the user to either use their location (provided by device) or a google map marker to choose their coordinates. I have succeeded at obtaining the coordinates from the map or device, however I am having trouble now creating a point from them to save into the db.

I've read the documentation and tried adding this code to my to my initializer:

initializer/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

Gemfile:

gem 'activerecord-postgis-adapter'

gem 'rgeo'

gem 'rgeo-activerecord'

Migration:

def change
 add_column :monuments, :grid_ref, :point, geographic: true
end

I get this error in the rails console when trying to create a point:

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'

I took this approach after reading this demonstration which suggests that the model understands WKT string implicitly, internally converting it to a "point" object.


回答1:


Use st_point, not point as the type:

add_column :monuments, :grid_ref, :st_point, geographic: true

Postgresql added a point type, so the type name in the postgis adapter was changed to st_point.

See https://github.com/rgeo/activerecord-postgis-adapter#point-and-polygon-types-with-activerecord-42:

Prior to version 3, the point and polygon types were supported. In ActiveRecord 4.2, the Postgresql adapter added support for the native Postgresql point and polygon types, which conflict with this adapter's types of the same names. The PostGIS point type must be referenced as st_point, and the PostGIS polygon type must be referenced as st_polygon.




回答2:


Found the solution. SRID must be specified, geographic_factory is now spherical_factory, and the point is a method invoked on the spherical factory of the specified SRID.

For the time being, I've implemented the following helper method, which works with rails 4.2.6, postgis and postgresql.

Please note that the factory takes the longitude parameter first :)

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

Moving forward, if you are following the same spacial configuration tutorial that I am, you will notice that the row created in this way will fail. I addressed this by replacing the :point column with :geographic column. The migration code is below.

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


来源:https://stackoverflow.com/questions/36775869/rgeo-error-attempting-to-create-point-from-lat-lon

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!