你如何跳过失败的迁移? (rake db:migrate)

时间:2012-01-10 21:26:57

标签: ruby-on-rails rake rails-migrations

我似乎无法找到允许我跳过迁移的选项或任何内容。

我知道你在想什么:“你永远不应该这样做......”

我需要跳过迁移,该迁移会更改我的开发数据库中不存在的特定用户记录。我不想更改迁移,因为它不是我应该使用的源代码的一部分。有没有办法跳过迁移或跳过失败的迁移?

提前致谢!

7 个答案:

答案 0 :(得分:58)

我认为您应该将违规迁移修复为不那么脆弱,我猜这几个if语句和rescue就足够了。

但是,如果修复迁移确实不是一种选择,你可以用各种方式伪造它。首先,您可以注释掉迁移方法,运行rake db:migrate,然后取消注释(或还原)违规迁移。

你也可以在数据库中伪造它,但是除非你知道你正在做什么,否则你不介意在你(不可避免地)犯错误的时候手动修补它时,不建议使用这种类型的chicanry。您的数据库中有一个名为schema_migrations的表,其中有一个名为varchar(255)的{​​{1}}列; version使用此表来跟踪已应用的迁移。您需要做的就是插入适当的db:migrate值,version将认为迁移已完成。找到有问题的迁移文件:

rake db:migrate

然后进入你的数据库说:

db/migrate/99999999999999_XXXX.rb

其中insert into schema_migrations (version) values ('99999999999999'); 当然是迁移文件名中的数字。然后运行99999999999999应该跳过该迁移。

我会在第三个选项之前使用第二个选项,我只包括“hack rake db:migrate”选项以获得完整性。

答案 1 :(得分:16)

我有一个问题,我有一个迁移来添加已经存在的表,所以在我的情况下我也不得不跳过这个迁移,因为我收到了错误

SQLite3::SQLException: table "posts" already exists: CREATE TABLE "posts"

我只是注释掉了create table方法的内容,运行了迁移,然后取消注释掉了。这是一种解决它的手动方式,但它有效。见下文:

class CreatePosts < ActiveRecord::Migration
  def change
    # create_table :posts do |t|
    #   t.string :title
    #   t.text :message
    #   t.string :attachment
    #   t.integer :user_id
    #   t.boolean :comment
    #   t.integer :phase_id

    #   t.timestamps
    # end
  end
end

答案 2 :(得分:15)

这是一次性错误的好方法。

db:migrate:up VERSION=my_version

这将运行一个特定迁移的“向上”操作。 (如果需要,也可以反过来,只需将“up”替换为“down”。)这样,您可以运行将来迁移,使旧版(需要跳过)工作,或者只运行每个有选择地进行迁移。

我也相信您可以通过这种方式重做迁移:

rake db:migrate:redo VERSION=my_version

我个人没有尝试过这种方法,所以YMMV。

答案 3 :(得分:7)

如果你必须这样做,你的应用程序的迁移就搞砸了!

插入所有缺少的迁移:

def insert(xxx)
  ActiveRecord::Base.connection.execute("insert into schema_migrations (version) values (#{xxx})") rescue nil
end

files = Dir.glob("db/migrate/*")
files.collect { |f| f.split("/").last.split("_").first }.map { |n| insert(n) }

答案 4 :(得分:1)

而不是跳过迁移,您可以使迁移变得智能,添加一些IF,这样您就可以检查“特定用户”

答案 5 :(得分:1)

有时,有必要使用绝对正确的迁移重新填充schema_migrations ... 仅适用于此用途我创建了此方法

def self.insert_missing_migrations(stop_migration=nil)
  files = Dir.glob("db/migrate/*")
  timestamps = files.collect{|f| f.split("/").last.split("_").first}
  only_n_first_migrations = timestamps.split(stop_migration).first

  only_n_first_migrations.each do |version|
    sql = "insert into `schema_migrations` (`version`) values (#{version})"
    ActiveRecord::Base.connection.execute(sql) rescue nil
  end
end

您可以将其复制粘贴到您想要的任何模型中,并从控制台

中使用它
YourModel.insert_missing_migrations("xxxxxxxxxxxxxx")

(或其他方式)

其中"xxxxxxxxxxxxxx" - 是您希望停止插入的迁移时间戳(您可以将其留空)

<强> !!!只有在你完全理解你会得到什么结果时才使用它!

答案 6 :(得分:0)

要跳过所有未完成的迁移,请在您的终端中运行此操作:

echo "a = [" $(rails db:migrate:status | grep "down" | grep -o '[0-9]\{1,\}' | tr '\n' ', ') "];def insert(b);ActiveRecord::Base.connection.execute(\"insert into schema_migrations (version) values (#{b})\") rescue nil;end;a.map { |b| insert(b)}" | xclip

(对于macOS,请使用pbcopy而不是xclip)

然后在rails控制台中CTRL-V结果:

a = [ 20180927120600,20180927120700 ];def insert(b);ActiveRecord::Base.connection.execute("insert into schema_migrations (version) values (#{b})") rescue nil;end;a.map { |b| insert(b)}

然后按Enter。

您可以通过在执行该行之前从数组 a 中删除它们来更改要跳过的迁移列表。