【问题标题】:How do you skip failed migrations? (rake db:migrate)如何跳过失败的迁移? (耙分贝:迁移)
【发布时间】:2012-02-07 07:19:01
【问题描述】:

我似乎找不到允许我跳过迁移的选项或任何东西。

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

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

提前致谢!

【问题讨论】:

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


    【解决方案1】:

    我认为你应该修复有问题的迁移,使其不那么脆弱,我猜几个 if 语句和一个 rescue 就足够了。

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

    您也可以在数据库中伪造它,但不推荐这种诡计,除非您知道自己在做什么,并且不介意在(不可避免地)犯错时手动修补。在您的数据库中有一个名为schema_migrations 的表,其中有一个名为versionvarchar(255) 列; db:migrate 使用此表来跟踪已应用的迁移。您需要做的就是插入适当的version 值,rake db:migrate 会认为迁移已经完成。找到有问题的迁移文件:

    db/migrate/99999999999999_XXXX.rb
    

    然后进入你的数据库并说:

    insert into schema_migrations (version) values ('99999999999999');
    

    其中99999999999999 当然是迁移文件名中的数字。然后运行 ​​rake db:migrate 应该会跳过该迁移。

    我会在第三个之前选择第二个选项,为了完整起见,我只包括“hack schema_versions”选项。

    【讨论】:

    • 是的,我只是暂时停止了有问题的迁移。我个人会创建正确的 If 语句,或者只是让它检查生产环境,但显然处理迁移的人不相信在开发时使用 db:migrate =P 谢谢
    • @hmind:“处理迁移的人不相信在开发时使用 db:migrate”。天啊。发布到您的生产系统一定是一段超级快乐的快乐时光!
    • 幸好我也不会​​处理哈哈
    【解决方案2】:

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

    db:migrate:up VERSION=my_version

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

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

    rake db:migrate:redo VERSION=my_version

    我没有亲自尝试过这种方法,所以YMMV。

    【讨论】:

    • 非常简洁,适合向上迁移。
    【解决方案3】:

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

    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
    

    【讨论】:

      【解决方案4】:

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

      插入所有缺失的迁移:

      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) }
      

      【讨论】:

      • 不一定。例如,如果您将生产数据库 pg_restore 到您的开发机器以解决生产数据问题。当您没有所有信息时,不要这么快告诉别人他们做错了。
      • @MikeBethany:就我而言,那是我不得不使用它的时候,一切都变得一团糟,我没有时间理解为什么会这样。关于pg_restore,我猜它也应该恢复schema_migrations表吧?
      • 是的,当然schema_migrations表只是数据库中的一个表。重新阅读您的标题,我可以看到另一种解释。我最初将其读作“您没有正确编写迁移”。我认为您的实际意思是“迁移存在问题”。但这很明显,因此问题,所以我假设“你搞砸了”的意思。我的错。
      【解决方案5】:

      要跳过所有待处理的迁移,请在终端中运行:

      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)

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

      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 中删除来更改要跳过的迁移列表。

      【讨论】:

      • 在您在本地转储数据库的生产版本的情况下非常有用。谢谢!
      【解决方案6】:

      您可以让您的迁移更智能,而不是跳过迁移,向它添加一些 IF,这样您就可以检查“特定用户”

      【讨论】:

      • 是的,如果我编写了迁移,我会这样做。但我没有,我也不想乱搞我不应该真正接触的部分来源,所以我只是暂时将它们删掉了。
      【解决方案7】:

      有时,有必要用绝对正确的迁移重新填充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" - 是迁移的时间戳,在此之前您要停止插入(您可以将其留空)

      !!!只有当你完全明白你会得到什么结果时才使用它!!!

      【讨论】:

        猜你喜欢
        • 2014-07-27
        • 2012-01-14
        • 1970-01-01
        • 1970-01-01
        • 2013-03-11
        • 1970-01-01
        • 2018-02-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多