回滚失败的Rails迁移

你如何回滚失败的导轨迁移? 我希望rake db:rollback能够撤销失败的迁移,但不会,它会回滚先前的迁移(失败的迁移减去一个)。 而rake db:migrate:down VERSION=myfailedmigration也不起作用。 我已经遇到了这几次,这是非常令人沮丧的。 这是我为复制问题所做的简单testing:

 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:迁移============================================= ========
 -  add_column(:assets,:test,:integer)
    - > 0.0932s
 -  add_column(:asset,:error)
耙中止!
发生错误,所有后来的迁移取消:

错误的参数数量(2为3)

好的,让我们回滚一下:

 $ rake db:rollback
 == AddLevelsToRoles:还原============================================= ==
 -  remove_column(:roles,:level)
    - > 0.0778s
 == AddLevelsToRoles:恢复(0.0779s)======================================

是吧? 这是我在SimpleTest之前的最后一次迁移,而不是失败的迁移。 (哦,如果迁移输出包含版本号,那将会很好。)

所以让我们尝试运行失败的迁移SimpleTest:

 $ rake db:migrate:down VERSION = 20090326173033
 $

没有任何反应,也没有输出。 但也许它运行迁移吗? 因此,让我们修复SimpleTest迁移中的语法错误,并尝试再次运行它。

 $ rake db:migrate:up VERSION = 20090326173033
 == SimpleTest:迁移============================================= ========
 -  add_column(:assets,:test,:integer)
耙中止!
 Mysql ::错误:重复的列名'test':ALTER TABLE'assets` ADD`test` int(11)

不。 显然迁移:下来没有工作。 这不是失败,它只是不执行。

除了手动进入数据库并删除它,然后运行testing,没有办法摆脱那个重复的表。 有一个比这更好的方法。

不幸的是,你必须手动清理MySQL失败的迁移。 MySQL不支持事务性数据库定义更改。

Rails 2.2包括PostgreSQL的事务性迁移。 Rails 2.3包括SQLite的事务性迁移。

这对您现在的问题并没有什么帮助,但是如果您在将来的项目中有数据库select,我推荐使用支持事务性DDL的方法,因为它使迁移变得更加愉快。

更新 – 这在2017年依然如此,在Rails 4.2.7和MySQL 5.7上,由Alejandro Babio在另一个答案中报告。

要转到指定的版本,只需使用:

 rake db:migrate VERSION=(the version you want to go to) 

但是,如果迁移部分失败,则必须先清除迁移。 一种方法是:

  • 编辑迁移的down方法以撤消工作的部分
  • 迁移回到之前的状态(您开始的地方)
  • 修复迁移(包括撤消您的更改)
  • 再试一次

好的,伙计们,这是你真正做到的。 我不知道上面的答案是在说什么。

  1. 找出升迁中的哪一部分工作。 评论这些。
  2. 同时注释/删除已经破解的部分迁移。
  3. 再次运行迁移。 现在它将完成迁移的非破坏部分,跳过已经完成的部分。
  4. 取消注释在第1步中注释的迁移位。

如果你想确认你已经有了它,你可以再次迁移和备份。

我同意你应该尽可能使用PostgreSQL。 但是,如果您遇到MySQL问题,可以先尝试在您的testing数据库上进行迁移,从而避免大部分这些问题:

 rake db:migrate RAILS_ENV=test 

您可以恢复到之前的状态,然后再次尝试

 rake db:schema:load RAILS_ENV=test 

这样做的简单方法是将所有的操作都包装在一个事务中:

 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某些types的操作不能通过事务恢复。 一般情况下,表的变化(删除表,删除或添加列等)不能回滚。

在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)中search到这个动作之后,我发现只有Sqlite3和PostgreSql支持事务,并且默认情况下它不被支持。

编辑因此,当前答案的原始问题:一个失败的MySQL迁移必须手动修复。

从控制台运行下来的迁移:

http://gilesbowkett.blogspot.com/2007/07/how-to-use-migrations-from-console.html (点击进入他的贴图)

我有一个错字(在“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 

结束

然后你的问题(不能撤消部分失败的迁移)。 一些失败的谷歌search后,我跑这个:

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 

结束

正如你所看到的,我只是手动添加了修正线,然后再将其移除,然后再检查。

上面的Alejandro Babio的答案提供了最好的答案。

我想添加一个额外的细节:

myfailedmigration迁移迁移失败时,它不被视为已应用,可以通过运行rake db:migrate:status来validation,这将显示类似于以下内容的输出:

 $ 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;进行反转alter table assets drop column test; 查询。