【问题标题】:How to create a migration to remove an index only if it exists, rather than throwing an exception if it doesn't?如何创建迁移以仅在索引存在时删除索引,而不是在不存在时抛出异常?
【发布时间】:2014-02-15 08:08:15
【问题描述】:

目前,如果books 表没有created_atupdated_at 字段,则当前迁移可能会失败:

class AddTimestampIndexes < ActiveRecord::Migration
  def up
    remove_index :books, :created_at
    remove_index :books, :updated_at

    add_index  :books, :created_at
    add_index  :books, :updated_at
  end

  def down
    remove_index :books, :created_at
    remove_index :books, :updated_at
  end
end

如果remove_index 未能删除索引而不是引发错误,它是否会采取任何选项静默继续?

【问题讨论】:

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


    【解决方案1】:

    您可以在迁移中使用index_exists? 方法来测试您需要删除的索引是否确实存在。

    在此处查看文档: http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/index_exists%3F

    我还没有测试过,但你应该可以使用这样的东西:

    class AddTimestampIndexes < ActiveRecord::Migration
      def up
        remove_index :books, :created_at if index_exists?(:books, :created_at)
        remove_index :books, :updated_at if index_exists?(:books, :updated_at)
    
        add_index  :books, :created_at
        add_index  :books, :updated_at
      end
    
      def down
        remove_index :books, :created_at
        remove_index :books, :updated_at
      end
    end
    

    虽然,从表面上看,您真的只想在它们不存在的情况下创建它们? 这可能更适合您的迁移:

    class AddTimestampIndexes < ActiveRecord::Migration
      def up
        add_index  :books, :created_at unless index_exists?(:books, :created_at)
        add_index  :books, :updated_at unless index_exists?(:books, :updated_at)
      end
    
      def down
        remove_index :books, :created_at
        remove_index :books, :updated_at
      end
    end
    

    【讨论】:

      【解决方案2】:

      还有index_name_exists?(table_name, index_name) 方法可以让你通过它的名字来检查一个索引。这有助于检查是否存在多列索引。

      文档 - index_name_exists

      【讨论】:

      • 不幸的是,它只会检查给定名称的索引是否存在,而index_exists? 将检查与给定定义匹配的索引(正确的列等)
      【解决方案3】:

      Rails 6.1+ if_exists / if_not_exists 选项

      Rails 6.1 向remove_index 添加了if_exists 选项,以便在删除索引时不会引发错误。

      Rails 6.1 向add_index 添加了if_not_exists 选项,以便在已添加索引时不会引发错误。

      因此,您的迁移可以通过以下方式重写:

      class AddTimestampIndexes < ActiveRecord::Migration
        def up
          remove_index :books, :created_at, if_exists: true
          remove_index :books, :updated_at, if_exists: true
      
          add_index :books, :created_at
          add_index :books, :updated_at
        end
      
        def down
          remove_index :books, :created_at, if_exists: true
          remove_index :books, :updated_at, if_exists: true
        end
      end
      

      以下是对应 PR 的链接列表:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-11-16
        • 2016-05-27
        • 1970-01-01
        • 1970-01-01
        • 2010-10-15
        • 1970-01-01
        • 2015-09-24
        相关资源
        最近更新 更多