如何回滚失败的rails迁移?我希望rake db:rollback
可以撤消失败的迁移,但不会,它会回滚先前的迁移(失败的迁移减去1)。并且rake db:migrate:down VERSION=myfailedmigration
也不起作用。我已经碰到了几次,这非常令人沮丧。这是我为复制问题所做的简单测试:
class SimpleTest < ActiveRecord::Migration
def self.up
add_column :assets, :test, :integer
# the following syntax error will cause the migration to fail
add_column :asset, :test2, :integer
end
def self.down
remove_column :assets, :test
remove_column :assets, :test2
end
end
结果:
== SimpleTest: migrating ===================================================== -- add_column(:assets, :test, :integer) -> 0.0932s -- add_column(:asset, :error) rake aborted! An error has occurred, all later migrations canceled: wrong number of arguments (2 for 3)
好的,让我们回滚一下:
$ rake db:rollback == AddLevelsToRoles: reverting =============================================== -- remove_column(:roles, :level) -> 0.0778s == AddLevelsToRoles: reverted (0.0779s) ======================================
是吗?这是我在SimpleTest之前的最后一次迁移,而不是失败的迁移。 (哦,如果迁移输出包含版本号,那就太好了。)
因此,让我们尝试运行失败的迁移SimpleTest:
$ rake db:migrate:down VERSION=20090326173033 $
没有任何事情发生,也没有输出。但也许它还是进行了迁移?因此,我们修复SimpleTest迁移中的语法错误,并尝试再次运行它。
$ rake db:migrate:up VERSION=20090326173033 == SimpleTest: migrating ===================================================== -- add_column(:assets, :test, :integer) rake aborted! Mysql::Error: Duplicate column name 'test': ALTER TABLE `assets` ADD `test` int(11)
不。显然迁移:down不起作用。它并没有失败,它只是没有执行。
除了手动进入数据库并删除它,然后运行测试之外,无法摆脱该重复的表。必须有一个比这更好的方法。
答案 0 :(得分:75)
不幸的是,您必须手动清理MySQL的失败迁移。 MySQL不支持事务数据库定义更改。
Rails 2.2包括PostgreSQL的事务性迁移。 Rails 2.3包括SQLite的事务性迁移。
这对您现在的问题并没有真正的帮助,但如果您在将来的项目中可以选择数据库,我建议使用支持事务DDL的数据库,因为它使迁移更加愉快。
更新 - 这在2017年仍然如此,在Rails 4.2.7和MySQL 5.7上,亚历杭德罗·巴比奥在另一个答案中报道。
答案 1 :(得分:20)
要转到指定版本,请使用:
rake db:migrate VERSION=(the version you want to go to)
但如果迁移失败,你必须先清理它。一种方法是:
down
方法,只撤消有效的up
部分down
的更改)答案 2 :(得分:18)
如果您想验证自己是否已立即恢复,可以再次向下迁移。
答案 3 :(得分:12)
我同意你应该尽可能使用PostgreSQL。但是,当您遇到MySQL时,可以通过首先在测试数据库上进行迁移来避免大多数这些问题:
rake db:migrate RAILS_ENV=test
您可以恢复到之前的状态,然后使用
重试rake db:schema:load RAILS_ENV=test
答案 4 :(得分:9)
在2015年使用Rails 4.2.1和MySQL 5.7时,无法使用Rails提供的标准rake操作修复失败的迁移,就像在2009年一样。
MySql不支持回滚DDL语句(MySQL 5.7 Manual)。并且Rails无法做任何事情。
另外,我们可以检查Rails是如何完成工作的:迁移是wrapped in a transaction,具体取决于连接适配器如何响应:supports_ddl_transactions?
。在rails source(v 4.2.1)中搜索此操作后,我发现只有Sqlite3和PostgreSql支持交易,而default则不支持。{/ p>
修改强> 因此,对原始问题的当前答案:必须手动修复失败的MySQL迁移。
答案 5 :(得分:8)
执行此操作的简单方法是将所有操作包装在事务中:
class WhateverMigration < ActiveRecord::Migration
def self.up
ActiveRecord::Base.transaction do
...
end
end
def self.down
ActiveRecord::Base.transaction do
...
end
end
end
正如Luke Francl所说,“MySql [的MyISAM表格不支持交易” - 这就是为什么你可能会考虑避免使用MySQL或特别是MyISAM。
如果你正在使用MySQL的InnoDB,那么上面的工作就可以了。任何向上或向下的错误都将退出。
BE AWARE 某些类型的操作无法通过交易恢复。通常,无法回滚表更改(删除表,删除或添加列等)。
答案 6 :(得分:1)
从控制台运行向下迁移:
http://gilesbowkett.blogspot.com/2007/07/how-to-use-migrations-from-console.html(点击查看他的牧师)
答案 7 :(得分:1)
我有一个拼写错误(在“add_column”中):
def self.up
add_column :medias, :title, :text add_colunm :medias, :enctype, :text
端
def self.down
remove_column :medias, :title remove_column :medias, :enctype
端
然后你的问题(无法撤消部分失败的迁移)。经过一些谷歌搜索失败后我跑了这个:
def self.up
remove_column :medias, :title add_column :medias, :title, :text add_column :medias, :enctype, :text
端
def self.down
remove_column :medias, :title remove_column :medias, :enctype
端
正如你所看到的那样,我只是手工添加了校正线,然后在我检查之前再将其删除。
答案 8 :(得分:1)
我想补充一个额外的细节:
当myfailedmigration
迁移失败时,它不会被视为已应用,并且可以通过运行rake db:migrate:status
来验证,这将显示类似于以下内容的输出:
$ rake db:migrate:status
database: sample_app_dev
Status Migration ID Migration Name
--------------------------------------------------
up 20130206203115 Create users
...
...
down 20150501173156 Test migration
对于失败的迁移执行add_column :assets, :test, :integer
的剩余影响必须在数据库级别使用alter table assets drop column test;
查询进行反转。