Rails 迁移更改时间到保留数据的日期时间

Rails migration change time to datetime preserving data

我需要不时更改我的专栏 'start_time' (我说的 datetime 和 timestamp 是一回事吗?注意:我在 postgres 上)

class ChangeStartTimeToBeDatetimeInAssignments < ActiveRecord::Migration[5.0]
  def up
    change_column :assignments, :start_time, :datetime
  end
  def down
    change_column :assignments, :start_time, :time
  end
end

列中的数据很重要所以不能删除...

注意:这里是 json 输出的片段,仅显示“start_time”部分(如果重要的话)

"start_time":"2000-01-01T12:00:00"

迁移时出现这个错误:

PG::DatatypeMismatch: ERROR:  column "start_time" cannot be cast automatically to type timestamp without time zone
HINT:  You might need to specify "USING start_time::timestamp without time zone".

运行 此迁移...

class ChangeStartTimeToBeDatetimeInAssignments < ActiveRecord::Migration[5.0]
  def up
    change_column :assignments, :start_time, :datetime, 'USING start_time::timestamp without time zone'
  end
  def down
    change_column :assignments, :start_time, :time
  end
end

给出这个错误...

== 20210916230930 ChangeStartTimeToBeDatetimeInAssignments: migrating =========
-- change_column(:assignments, :start_time, :datetime, "USING start_time::timestamp without time zone")
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

no implicit conversion of Symbol into Integer

我做错了什么?

如何将“时间”迁移到“日期时间”?

如何修改迁移并按照建议添加“USING start_time::timestamp without time zone”?

(我说的 datetime 和 timestamp 是一回事吗?)

感谢您的宝贵时间。

为了可读性,一步一步来吧。这也将有助于定义正确的 down 方法以确保回滚不会出错。

class ChangeStartTimeToBeDatetimeInAssignments < ActiveRecord::Migration[5.0]
  def up
    # add a temporary column
    add_column :assignments, :start_time_datetime, :datetime
    
    # add the the current start_time as datetime to the temporary column for each entry
    Assignment.all.each do |assignment|
      assignment.update(start_time_datetime: assignment.start_time.to_datetime)
    end

    # drop the old time column
    remove_column :assignments, :start_time
    
    # rename the temporary column to start_time   
    rename_column :assignments, :start_time_datetime, :start_time
  end

  def down
    add_column :assignments, :start_time_time, :time
    
    Assignment.all.each do |assignment|
      assignment.update(start_time_time: assignment.start_time.to_time
    end

    remove_column :assignments, :start_time
    rename_column :assignments, :start_time_time, :start_time
  end
end

为了确保更新循环不会因为数据不一致而出错并留下一半混乱的数据,您可以将更新部分包装到 https://api.rubyonrails.org/v6.1.4/classes/ActiveRecord/Transactions/ClassMethods.html