问题
So i made a migration like this
class AddDatetimeAttrToUsers < ActiveRecord::Migration
def change
change_column :users, :oauth_expires_at, :datetime
end
end
on my local environment it works just fine but when i try
heroku run rake db:migrate i get an error
ERROR: column "oauth_expires_at" cannot be cast automatically to type timestamp without time zone
HINT: Specify a USING expression to perform the conversion.
When i searched it, i created a new migration like this as best practice for changing an attribute using change.
class PutDatetimeFieldToUsersExpireAtColumn < ActiveRecord::Migration
def change
remove_column :users, :oauth_expires_at
add_column :users, :oauth_expires_at, :datetime
end
end
so i tried to use rake db:rollback to delete last migration and add this one informing me that the last migration is irreversible.
my question is, is there a way to actually rollback on an irreversible migration or should i just migrate using the new migration above?
回答1:
In your example, you have the following migration file:
class AddDatetimeAttrToUsers < ActiveRecord::Migration
def change
change_column :users, :oauth_expires_at, :datetime
end
end
You have already run rake db:migrate
successfully in your dev environment. You are running sqlite3 locally and PG on heroku, and and as a result, your change_column
works locally, but it fails on PG because PG expects a 'using' statement.
The fix this, step 1 is to edit your migration file to add an up and down migration as suggested by Yohann above. Yes, you should do this even though you have already raked this migration.
class AddDatetimeAttrToUsers < ActiveRecord::Migration
def up
change_column :users, :oauth_expires_at, :datetime
end
def down
change_column :users, :oauth_expires_at, :time (or whatever type existed before datetime)
end
end
Now you can run rake db:rollback
and avoid the irreversible migration error, but only if you HAVE NOT ADDED ADDITIONAL MIGRATIONS. If you have added additional migrations you will need to specify how far back to go using rake db:down VERSION=2018xxxxxxx
or rake db:rollback STEP=X
.
Now edit the migration so it plays nice with pg and sqlite3:
class AddDatetimeAttrToUsers < ActiveRecord::Migration
def up
change_column :users, :oauth_expires_at, :datetime, using: 'oauth_expires_at::datetime'
end
def down
change_column :users, :oauth_expires_at, :time
end
Now you should be able to rake db:migrate, push to heroku, and heroku run rake db:migrate and move on.
Finally, you should get pg working locally to match your production environment.
回答2:
You can define up
and down
methods instead of change
in your migration.
Here is an example:
def up
connection.execute %(create or replace view name_of_the_db_view)
end
def down
connection.execute %(drop view name_of_the_db_view)
end
With it you will be able to migrate
and rollback
the previously irreversible migration like it was a normal migration.
回答3:
It seems you need to specify a current type of oauth_expires_at column, because at rollback Rails should know it to create the column. I mean following:
remove_column :users, :oauth_expires_at, :string
回答4:
if you dare to lose your data on your local database then you can recover from irreversible migration(by losing your database data) by doing these steps:
1- first deleting your database(assuming that you are in the development environment and just ok to delete the database in this environment - your test database will also be gone)
export RAILS_ENV=development
rake db:drop
2- Reloading your schema file:
rake db:schema:load
3- To see your current migration files:
rake db:migrate:status
4- Delete the migration that you want to get rid of:
rake db:migrate:down VERSION=xxxxxx
rails destroy migration migration_name
5- Then you can make db:migrate to migrate your migrations.
rake db:migrate
来源:https://stackoverflow.com/questions/31867927/irreversible-migration-can-it-be-fixed-rails-4