Rails迁移到Postgres问题(时间)

时间:2015-07-30 14:55:53

标签: ruby-on-rails postgresql heroku sqlite

我已经在本地工作了一段时间的rails应用程序,并且大部分应用程序都保留在localhost中。我已经对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上运行。

2 个答案:

答案 0 :(得分:1)

问题是timestampz的信息多于time。来自fine manual

  

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

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

  

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

但是,您的评论表明您并不关心您拥有的数据,因此我只需通过一次迁移删除现有列,然后使用其他迁移重新添加该列:

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,这样你就不用担心了。

答案 1 :(得分:1)

您可以使用明确的USING表达式和类型转换来执行此操作:

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