如何回滚失败的 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)

没有。显然 migrate:down 不起作用。这不是失败,只是没有执行。

除了手动进入数据库并删除它,然后运行测试之外,没有办法删除重复的表。一定有比这更好的方法。

有帮助吗?

解决方案

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

2.2的Rails包括用于PostgreSQL的事务的迁移。轨道2.3包括用于SQLite的事务的迁移。

这并不能真正帮助您的问题的权利,但如果你对未来的项目数据库的选择,我建议,因为它使迁移更加舒适使用一个为事务DDL支持。

更新 - 这仍然是正确的,2017年,on Rails的4.2.7和MySQL 5.7,亚历杭德罗·Babio在这里另一个答案报道

其他提示

去一个指定的版本仅使用:

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

但是,如果一个移徙失败的一部分的方式,你就必须把它清理干净的第一个。一个办法将是:

  • 编辑 down 方法迁移到刚才撤销的部分 up 这工作
  • 迁移回到以前的状态(开始)
  • 解决移徙(包括撤消你的改变 down)
  • 再试一次

好吧,伙计们,这里就是你如何实际上这样做。我不知道什么,上述的答案都在谈论。

  1. 找出其中的一部分迁移工作。评论那些出来。
  2. 还注释放/清除的一部分迁移,破产了。
  3. 再次运行迁移。现在,它将完成该非破损的部件的移徙,跳过这部分已经完成。
  4. 取消位的移徙你说出于步骤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语句的回滚(at MySQL 5.7 手册)。Rails 对此无能为力。

另外,我们可以检查 Rails 是如何完成这项工作的:迁移是 包含在交易中 取决于连接适配器如何响应 :supports_ddl_transactions?. 。在rails源代码(v 4.2.1)搜索此操作后,我发现只有 SQLite3PostgreSQL 支持交易,并通过 默认 它不受支持。

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

在简单的方法来做到这一点是包装你的所有行动在一个事务中:

class WhateverMigration < ActiveRecord::Migration

 def self.up
    ActiveRecord::Base.transaction do
...
    end
  end

  def self.down
    ActiveRecord::Base.transaction do
...
    end
  end

end

由于卢克Francl指出,“MySQL的[的MyISAM表不]支持交易。” - 这就是为什么你会考虑避免一般或至少的MyISAM特别的MySQL

如果你使用MySQL的InnoDB的,那么上面会工作得很好。在向上或向下的任何错误将回退。

<强>注意某些类型的动作不能经由交易还原。一般地,表的更改(删除表,删除或添加的列,等)不能被回滚。

运行刚刚从控制台向下迁移:

HTTP://gilesbowkett.blogspot .COM / 2007/07 /如何使用的的迁移从 - console.html (点击进入他的pastie)

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

,然后你的问题(无法撤消部分失败的迁移)。后一些失败使用Google我跑这样的:

  

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,这将显示出类似下列的输出进行验证:

$  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;查询数据库级别被颠倒。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top