回滚失败的Rails迁移

时间:2009-03-26 17:49:34

标签: mysql ruby-on-rails rails-activerecord rails-migrations

如何回滚失败的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不起作用。它并没有失败,它只是没有执行。

除了手动进入数据库并删除它,然后运行测试之外,无法摆脱该重复的表。必须有一个比这更好的方法。

9 个答案:

答案 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)

好的,大家好,这就是你实际做的方式。我不知道上面的答案在说什么。

  1. 确定向上迁移的哪个部分有效。评论那些。
  2. 同时注释掉/删除已破坏的部分迁移。
  3. 再次运行迁移。现在它将完成迁移的未破坏部分,跳过已经完成的部分。
  4. 取消注释您在步骤1中注释掉的迁移位。
  5. 如果您想验证自己是否已立即恢复,可以再次向下迁移。

答案 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)中搜索此操作后,我发现只有Sqlite3PostgreSql支持交易,而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;查询进行反转。