回滚失败的 Rails 迁移
-
22-08-2019 - |
题
如何回滚失败的 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。
你可以迁移下来,并再度回升,如果你想要验证是否已经得到它的权利。
我同意,你应该尽可能使用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)搜索此操作后,我发现只有 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
由于卢克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;
查询数据库级别被颠倒。