Rails迁移中的PostgreSQL点类型

6

我想使用PostgreSQL中的类型。我已经完成了:

rails g model Test point:point

由此产生的迁移是:

class CreateTests < ActiveRecord::Migration
  def change
    create_table :tests do |t|
      t.point :point

      t.timestamps
    end
  end
end

当我运行时:

rake db:migrate

结果如下:
    ==  CreateTests: migrating ====================================================
    -- create_table(:tests)
    rake aborted!
    An error has occurred, this and all later migrations canceled:

    undefined method `point' for #<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::TableDefinition:0x000000038991a0>/home/i/Dropbox/programming/ruby/rails_pg_for_tests/db/migrate/20140306151700_create_tests.rb:4:in `block in change'
    /home/i/.rvm/gems/ruby-1.9.3-p448/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract/schema_statements.rb:184:in `create_table'
    /home/i/.rvm/gems/ruby-1.9.3-p448/gems/activerecord-4.0.2/lib/active_record/migration.rb:625:in `block in method_missing'
    /home/i/.rvm/gems/ruby-1.9.3-p448/gems/activerecord-4.0.2/lib/active_record/migration.rb:597:in `block in say_with_time'
...

也许我需要安装PostGIS,但是如果我在PostgreSQL中已经有点类型,我不明白为什么需要它。我只需要存储纬度和经度,没有其他选项。

我应该如何使用这个点类型或者在这种情况下使用什么更好呢?

谢谢。


1
仅仅因为PostgreSQL有一个点类型,并不意味着ActiveRecord支持它。 - sevenseacat
1
point 类型来自于 PostgreSQL,与 PostGIS 的 geometry 类型无关。 - Mike T
6个回答

8
你可以将数据类型指定为字符串。
t.column 'point', 'point'

2
第一个 point 是列名,第二个是列类型。 - Daniel Rikowski

6

Rails 多年来一直支持 point。测试用例从 Rails 4.2 beta 开始存在。

如果你正在使用 Rails 4.2 或更新版本,你不应该遇到这个错误。我还没有在 4.2 beta 上进行测试。我只在 Rails 5.2 上测试过,而且不需要任何额外的 gem 就可以正常工作。

https://github.com/rails/rails/blob/24adc20ace69ec0fcf317e0a8d91d112478ba015/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb

用法:

迁移

class CreateAddresses < ActiveRecord::Migration[5.2]
  def change
    create_table :addresses do |t|
      t.point   :coordinate
    end
  end
end

创建一条新记录。
Address.create coordinate: ActiveRecord::Point.new(1, 1)

1
这是非常受欢迎的更新,尤其在编写最新版 Rails 6 和 activerecord-postgis-adapter gem 还不可用时。 - chemic

3

当执行迁移代码时,您会收到undefined method 'point' for #<ActiveRecord:...错误。

t.point :point

由于ActiveRecord中不存在point方法。

ActiveRecord原生支持以下数据类型

 :primary_key, :string, :text, :integer, :float, :decimal, :datetime, :timestamp, 
 :time, :date, :binary, :boolean

请参考ActiveRecord的官方文档
正如@bridiver所建议的,你可以选择指定除了ActiveRecord支持的数据类型(如上面列出的)之外的其他类型,使用t.column :point, 'point'。但是请注意,正如在 ActiveRecord 文档中引用的那样:

这不是数据库无关的,通常应该避免使用。

更新 我建议使用activerecord-postgis-adapter gem,如@euricovidal所建议的那样。它是pgsql的地理空间扩展,它作为PostGIS查询函数的包装器,并允许您编写具有地理感知的迁移。 它将允许您创建一个point类型,并且使用这个类型,您当前的语法应该可以工作。
例如,请参考PostGIS ActiveRecord Adapter:Creating Spatial Tables。此外,您还需要在database.yml文件中将adapter更新为postgis,才能使其正常工作。

请添加评论以描述为什么您要向下投票答案,这样我就可以改进答案,不要只是向下投票。 - Kirti Thorat
我给它投了反对票,因为它是错误的。您可以按照我下面概述的方式使用列来指定任意类型。 - bridiver
@bridiver 谢谢你提出的观点。我已经在我的回答中添加了解释。 - Kirti Thorat
使用PostGIS也有同样的注意事项,它不会是数据库无关的。 - bridiver
@bridiver 当涉及到数据库特定的事情时,在这种情况下,它当然会对两种情况都是数据库无关的。对于 OP(考虑可维护性和可用性问题),他是否希望选择不被当前 gem 主要支持的东西,或者使用专门为该需求设计的 gem 扩展,这仍然是一种偏好问题。 - Kirti Thorat
无论如何,这个警告都适用于两者,为什么要单独挑选其中一个,好像它不适用于另一个一样?两种解决方案都不是数据库无关的。 - bridiver

1

0

您很可能需要编辑config \ database.yml以引用postgis作为您的数据库适配器

default: &default
  adapter: postgis
  encoding: unicode
  pool: 5
  timeout: 5000
  host: localhost

development:
  <<: *default
  database: learning_rails
  username: brentpayne
  password:

你可能还想编辑你的迁移,将:point指定为geographic,这样你就可以计算距离了。

  t.point :point, :geographic => true

但是你遇到的错误与我留下的错误完全相同,当时我将我的适配器设置为postgresql。将其更改为postgis解决了我的问题。

参考资料:https://github.com/rgeo/activerecord-postgis-adapter#installation-and-configuration


0
如果您安装了georuby,则点数据类型将变得可用。
Gemfile
gem 'pg'
gem 'georuby'

在迁移中

def change
  create_table :space_table do |t|
    t.point :location
    t.timestamps
  end
end

您可以使用 model_object.location = [-33.233, 123.123] 来保存一个点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接