【问题标题】:Rails migration to Postgres issue (time)Rails 迁移到 Postgres 问题(时间)
【发布时间】:2015-07-30 14:55:52
【问题描述】:

我已经在本地开发 Rails 应用程序已有一段时间了,并且大部分应用程序都保留在本地主机中。我已经对 Heroku 进行了一次部署作为测试,并且从那以后开发了更多应用程序。好吧,现在我想将更新的版本推送到heroku,但我的时间最糟糕。首先,我经历并了解了一致性数据库的重要性(test/dev 使用 sqlite3,heroku 使用 postgres)。

我已将测试/开发数据库从 sqlite3 移至 postgres,这工作正常,但我在推送到本地没有的 heroku 时仍然遇到问题,即使我使用的是 postgres。

这是我得到的错误:

== 20150713172604 ChangingRoomTimeToDatetime: migrating =======================
-- change_column(:rooms, :start_time, :timestamptz)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::DatatypeMismatch: ERROR:  column "start_time" cannot be cast automatically to type timestamp with time zone
HINT:  Specify a USING expression to perform the conversion.
: ALTER TABLE "rooms" ALTER COLUMN "start_time" TYPE timestamptz/app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.8/lib/active_record/connection_adapters/postgresql/database_statements.rb:128:in `async_exec'

最初我对房间使用时间数据类型,直到我意识到日期也很重要:

class AddingTimeToRoomModel < ActiveRecord::Migration
  def change
    add_column :rooms, :start_time, :time
    add_column :rooms, :end_time, :time
  end
end

变化:

class ChangingRoomTimeToDatetime < ActiveRecord::Migration
  def change
    change_column :rooms, :start_time, :timestamptz
    change_column :rooms, :end_time, :timestamptz
  end
end

此时数据并不重要,因为数据库中唯一的数据是我不小心删除/丢弃的测试数据。我尝试使用 :timestamp 和 :timestamptz ,但我无法得到任何工作,并且很困惑为什么它可以在本地工作,但不能在 heroku 上工作。

【问题讨论】:

  • 您正在尝试将时间转换为完整的时间戳,时间戳应该与哪个日期一起使用?
  • 抱歉,我不完全确定您的意思。当我最初设置它时,我使用:时间然后意识到我需要日期,因为它是事件的一部分,所以我需要日期,所以切换到:日期时间。然后在使用 heroku/postgres 时开始在此迁移中出错。我不太在意时间戳,我只需要在这个字段上有日期和时间
  • 时间看起来像HH:MM:SS,但时间戳是YYYY-MM-DD HH:MM:SS,如果没有YYYY-MM-DD 部分,您无法将时间转换为时间戳。
  • 哦,我明白你的意思了,有没有办法设置默认值,或者我应该将初始 add_column 更改为时间戳和回滚迁移?正如我所说,除了一两个无关紧要的测试值之外,数据库中没有任何数据
  • 如果您不关心数据,那么只需在一个迁移中删除该列,然后在另一个迁移中添加新版本。

标签: ruby-on-rails postgresql heroku sqlite


【解决方案1】:

问题在于timestampztime 拥有更多信息。来自fine manual

timestamp with time zone
日期和时间,带时区
[...]
time
一天中的时间(无日期)

您可以在使用USING clause 将列类型转换为timestampz 时为您的时间添加一个日期:

可选的USING 子句指定如何从旧列值计算新列值;如果省略,则默认转换与从旧数据类型到新数据类型的赋值转换相同。如果没有从旧类型到新类型的隐式或赋值强制转换,则必须提供 USING 子句。

但是,您的 cmets 说您不关心您拥有的数据,所以我只需使用一次迁移删除现有列,然后使用另一次迁移重新添加该列:

class RemoveTimeFromRoomModel < ActiveRecord::Migration
  def change
    remove_column :rooms, :start_time
    remove_column :rooms, :end_time
  end
end

class ReAddTimeToRoomModel < ActiveRecord::Migration
  def change
    add_column :rooms, :start_time, :timestampz
    add_column :rooms, :end_time, :timestampz
  end
end

我不确定 SQLite 将如何处理 :timestampz,但它可能最终会成为 text。 OTOH,在一个数据库上开发并在另一个数据库上部署是一种痛苦和痛苦的捷径,所以我建议您将开发环境切换到 PostgreSQL,这样您就不必担心了。

【讨论】:

    【解决方案2】:

    您可以使用显式 USING 表达式和类型转换来做到这一点:

    change_column :rooms, :start_time, 'timestamptz using start_time::timestamptz'
    

    【讨论】:

      猜你喜欢
      • 2013-09-16
      • 1970-01-01
      • 2017-09-22
      • 1970-01-01
      • 2013-01-23
      • 2016-08-24
      • 2010-11-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多