如何创建迁移以仅在存在时删除索引,而不是抛出异常(如果不存在)?

The*_*mer 32 ruby-on-rails rails-migrations ruby-on-rails-4

目前,如果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
Run Code Online (Sandbox Code Playgroud)

remove_index如果无法删除索引而不是引发错误,是否采取任何选项以静默方式继续?

Jon*_*Jon 60

您可以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
Run Code Online (Sandbox Code Playgroud)

虽然从事物的外观来看,如果它们不存在,你真的只想创造它们吗?这可能更适合您的迁移:

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
Run Code Online (Sandbox Code Playgroud)


Mar*_*n13 12

Rails 6.1+ if_exists / if_not_exists 选项

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

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

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

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
Run Code Online (Sandbox Code Playgroud)

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


dvv*_*vrt 7

还有一种index_name_exists?(table_name, index_name)方法可以让您通过名称检查索引。它有助于检查多列索引的存在。

文档 - index_name_exists

  • 不幸的是,这只会检查给定名称的索引是否存在,而“index_exists?”将检查与给定定义匹配的索引(正确的列等) (2认同)