Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RGeo error attempting to create point from lat/lon

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.

like image 649
CrazyMyBeat Avatar asked Dec 16 '25 17:12

CrazyMyBeat


2 Answers

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
like image 57
dave Avatar answered Dec 19 '25 05:12

dave


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.

like image 37
tee Avatar answered Dec 19 '25 05:12

tee



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!