如何回滚失败的rails迁移?我希望这rake db:rollback
会撤消失败的迁移,但不会,它会回滚先前的迁移(失败的迁移减去一次).而且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不起作用.它并没有失败,它只是没有执行.
除了手动进入数据库并删除它,然后运行测试之外,没有办法摆脱那个重复的表.必须有一个比这更好的方法.
不幸的是,您必须手动清理MySQL的失败迁移.MySQL不支持事务数据库定义更改.
Rails 2.2包括PostgreSQL的事务性迁移.Rails 2.3包括SQLite的事务性迁移.
这对您现在的问题并没有真正的帮助,但如果您在将来的项目中可以选择数据库,我建议使用支持事务DDL的数据库,因为它使迁移更加愉快.
更新 - 这在2017年仍然如此,在Rails 4.2.7和MySQL 5.7上,Alejandro Babio在另一个答案中报告.
要转到指定版本,只需使用:
rake db:migrate VERSION=(the version you want to go to)
但如果迁移失败,你必须先清理它.一种方法是:
编辑down
迁移的方法,只是撤消那部分up
工作
迁移回先前状态(您开始的地方)
修复迁移(包括撤消对您的更改down
)
再试一次
好的,大家好,这就是你实际做的方式.我不知道上面的答案在谈论什么.
弄清楚向上迁移的哪个部分有效.评论那些.
同时注释掉/删除破坏的部分迁移.
再次运行迁移.现在它将完成迁移的未破坏部分,跳过已经完成的部分.
取消注释在步骤1中注释掉的迁移位.
如果要验证您是否已立即恢复,则可以再次向下迁移并重新备份.
我同意你应该尽可能使用PostgreSQL.但是,当您遇到MySQL时,可以通过首先在测试数据库上尝试迁移来避免大多数这些问题:
rake db:migrate RAILS_ENV=test
您可以恢复到之前的状态,然后重试
rake db:schema:load RAILS_ENV=test
在2015年使用Rails 4.2.1和MySQL 5.7时,无法使用Rails提供的标准rake操作修复失败的迁移,就像在2009年一样.
MySql不支持回滚DDL语句(在MySQL 5.7手册中).并且Rails无法做任何事情.
此外,我们可以检查Rails如何完成工作:迁移包含在事务中,具体取决于连接适配器的响应方式:supports_ddl_transactions?
.在rails source(v 4.2.1)中搜索此操作后,我发现只有Sqlite3和PostgreSql支持事务,默认情况下不支持.
编辑 因此,对原始问题的当前答案:必须手动修复失败的MySQL迁移.
执行此操作的简单方法是将所有操作包装在事务中:
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,那么上面的工作就可以了.任何向上或向下的错误都将退出.
要注意某些类型的操作无法通过事务还原.通常,无法回滚表更改(删除表,删除或添加列等).