When trying to set up indices on a set of mysql tables, a number of annoying errors can occur that necessitate re-running a migration.

This simple hack lets you specify a :force => true on add_index or remove_index calls.

# Allows you to specify indices to add in a migration that will only be created if they do not
# already exist, or to remove indices only if they already exist
module ActiveRecord
  module ConnectionAdapters
    class MysqlAdapter
 
      def add_index_with_unless_exists table_name, column_name, options = {}
        if options.kind_of?(Hash) && options.delete(:force)
          begin
            add_index_without_unless_exists table_name, column_name, options
          rescue
            if /^Mysql::Error: Duplicate key name /.match($!.message)
              puts "Failed to create index #{table_name} #{column_name} #{options.inspect}"
            else
              raise $!
            end
          end
        else
          add_index_without_unless_exists table_name, column_name, options
        end
      end
      alias_method_chain :add_index, :unless_exists
 
      def remove_index_with_unless_doesnt_exist table_name, options = {}
        if options.kind_of?(Hash) && options.delete(:force)
          begin
            remove_index_without_unless_doesnt_exist table_name, options
          rescue
            if /^Mysql::Error: Can't DROP/.match($!.message)
              puts "Failed to drop index #{table_name} #{options.inspect}"
            else
              raise $!
            end
          end
        else
          remove_index_without_unless_doesnt_exist table_name, options
        end
      end
      alias_method_chain :remove_index, :unless_doesnt_exist
 
    end
  end
end

Leave a Comment

Enclose code in <code lang="ruby"></code> if you care.
Preview your comment using the button below.