How to create a migration to remove an index only if it exists, rather than throwing an exception if it doesn't?
Right now, the current migration might fail, if the books
table doesn't have created_at
or updated_at
fields:
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
Does remove_index
take any options to silently proceed if it fails to remove the index rather than raising an error?
You can use the index_exists?
method within your migration to test whether the index you need to remove is actually there.
Take a look at the documentation here: http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/index_exists%3F
I've not tested it, but you should be able to use something like this:
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
Although, by the looks of things, you really only want to create them if they don't exist? This might be more appropriate for your migration:
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
There is also index_name_exists?(table_name, index_name)
method which let's you check for an index by it's name. It's helpful for checking for existence of multi-column indexes.
Documentation - index_name_exists
Rails 6.1+ if_exists / if_not_exists options
Rails 6.1 added if_exists
option to remove_index
in order to not raise an error when the index is already removed.
Rails 6.1 added if_not_exists
option to add_index
in order to not raise an error when the index is already added.
As a result, your migration can be rewritten in the following way:
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
Here is a list of the links to the corresponding PRs:
-
Add
if_exists
option toremove_index
, - Fix index options for if_not_exists/if_exists.