Home > Back-end >  Rails migration change time to datetime preserving data
Rails migration change time to datetime preserving data

Time:09-21

I need to change my column 'start_time' from time to datetime (Am I correct in that datetime and timestamp are the same thing? NOTE: I'm on 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

The data in the column is important so it can't be deleted...

Note: here is a snippet of the json output displaying only the "start_time" portion (if it matters)

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

This error occurs when I migrate:

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".

Running this migration...

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

Gives this error...

== 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

What am I doing wrong?

How do I migrate "time" to "datetime"?

How do I modify my migration and add "USING start_time::timestamp without time zone" as suggested?

(Am I correct in that datetime and timestamp are the same thing?)

Thank you for your time.

CodePudding user response:

For the sake of readability just make everything step by step. This also will help with defining a proper down method to make sure rollbacks won't error out.

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

To ensure that the update loop does not error out because of data inconsistency and leaving you with half messed up data you can wrap the update part into a https://api.rubyonrails.org/v6.1.4/classes/ActiveRecord/Transactions/ClassMethods.html

  • Related