9

How I should enter my multicolum indexes which contain functions into schema.rb ?

for example this DOESN'T work:

add_index "temporary_events", ["templateinfoid", "campaign", "date(gw_out_time)", "messagetype"], :name => "temporary_events_campaign_tinfoid_date_messagetype"

rake db:test:load

rake aborted!

PGError: ERROR: column "date(gw_out_time)" does not exist

: CREATE INDEX "temporary_events_campaign_tinfoid_date_messagetype" ON "temporary_events" ("templateinfoid", "campaign", "date(gw_out_time", "messagetype")

3 Answers 3

18

The built-in ActiveRecord method for creating indexes (add_index) does not support functions or any other more advanced features. Instead you can use execute to create the index with SQL:

execute <<-SQL
  CREATE INDEX temporary_events_campaign_tinfoid_date_messagetype
  ON temporary_events(templateinfoid, campaign, date(gw_out_time), messagetype);
SQL

Note that the use of execute in migrations can be problematic if you are not using the SQL schema format (config.active_record.schema_format = :sql). For more information, search for schema_format.

Sign up to request clarification or add additional context in comments.

1 Comment

To make this migration reversible, simply add to down: remove_index :temporary_events, :name => "temporary_events_campaign_tinfoid_date_messagetype"
5

I was able to get functional indexes out of Rails (3.1.3) migrations by removing a couple guard-rails!

  # lib/functional_indexes.rb
  module ActiveRecord
    module ConnectionAdapters
      module SchemaStatements
        #disable quoting of index columns to allow functional indexes (e.g  lower(full_name) )
        def quoted_columns_for_index(column_names, options = {})
          column_names
        end

        def index_name_for_remove(table_name, options = {})
          index_name = index_name(table_name, options)

          # disable this error check -- it can't see functional indexes
          #unless index_name_exists?(table_name, index_name, true)
          #  raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
          #end

          index_name
        end
      end
    end
  end

I had to make my own index names, though:

  class AddLowerCaseIndexes < ActiveRecord::Migration
    def up
      add_index :people, 'lower(full_name)', :name => "index_people_on_lower_full_name"
      add_index :people, 'lower(company)',   :name => "index_people_on_lower_company"
    end

    def down
      remove_index :people, :name => "index_people_on_lower_full_name"
      remove_index :people, :name => "index_people_on_lower_company"
    end
  end

(You probably don't need quotes around your index column names unless you are doing something insane like putting spaces or weird characters in them.)

(You are probably fine with postgres error messages when attempting to rollback non-existent indexes.)

Comments

1

If you are using pg_power gem(https://github.com/TMXCredit/pg_power), you can do it in the following way:

add_index(:comments, 'dmetaphone(author)', :using => 'gist')

1 Comment

The repo has been removed. The gem is not maintained since 2014. There is, probably a copy/fork of the original repo at: github.com/sfate/pg_power

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.