简体   繁体   中英

Rails migration to Postgres issue (time)

I've been working on a rails app locally for some time now and for the most part the application has stayed in localhost. I've made one deployment to Heroku as a test and have developed the application more since. Well now I am wanting to push newer versions to heroku but I am having the worst time. First off, I've lived and learned the importance of consistant databases (test/dev used sqlite3, heroku uses postgres).

I've moved the test/dev databases from sqlite3 to postgres which works fine, but I am still having issues when pushing to heroku that I am not having locally, even though I am using postgres.

Here is the error I am getting:

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

Originally I was using time datatype for rooms until I realized that date was important too:

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

Change:

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

Data is not important at this moment since the only data in database was test data that I've accidentally deleted/dropped anyway. I've tried to use :timestamp and :timestamptz but I just cannot get anything to work and am confused why it works locally but not on heroku.

The problem is that a timestampz has more information than a time . From the fine manual :

timestamp with time zone
both date and time, with time zone
[...]
time
time of day (no date)

You can add a date to your times while converting the column type to timestampz using a USING clause :

The optional USING clause specifies how to compute the new column value from the old; if omitted, the default conversion is the same as an assignment cast from old data type to new. A USING clause must be provided if there is no implicit or assignment cast from old to new type.

However, your comments say that you don't care about the data you have so I'd just drop the existing column with one migration and then re-add the column with another migration:

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

I'm not sure what SQLite will do with :timestampz though, it'll probably end up as text . OTOH, developing on one database and deploying on another is a shortcut to pain and suffering so I'd recommend that you switch your development environment to PostgreSQL so that you don't have to worry about it.

您可以USING显式的USING表达式和类型转换来完成此操作:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM