37

here is my migration in rails 3.2.2:

class CreateStatistics < ActiveRecord::Migration
  def change
    create_table :statistics do |t|
      t.string :name
      t.integer :item_id
      t.integer :value
      t.text :desc

      t.timestamps
      t.index [:name, :item_id]
    end

  end
end

and here is the migrate error:

==  CreateStatistics: migrating ===============================================
-- create_table(:statistics)
ActiveRecord::ConnectionAdapters::TableDefinition
rake aborted!
An error has occurred, all later migrations canceled:

undefined method `index' for #<ActiveRecord::ConnectionAdapters::TableDefinition:0xbd16888>

Tasks: TOP => db:migrate
(See full trace by running task with --trace)

what is the right way to create a index?

5 Answers 5

74

You can still add an index as a part of a "change" migration. You just have to do it outside of the call to create_table:

class CreateStatistics < ActiveRecord::Migration
  def change
    create_table :statistics do |t|
      t.string :name
      t.integer :item_id
      t.integer :value
      t.text :desc

      t.timestamps
    end

    add_index :statistics, [:name, :item_id]
  end
end

This correctly creates the table and then the index on an "up" migration and drops the index and then the table on a "down" migration.

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

1 Comment

A quick note: @Brandan's answer here is "righter" than injeckt's for the Rails 3 style migrations which allow change methods instead of old-style up and down methods. Both are fine, it just took me a minute to realize the difference.
4

so I change it to the old way, and it works. and I think there is a new way doing this by using change method.

class CreateStatistics < ActiveRecord::Migration
  def up
    create_table :statistics do |t|
      t.string :name
      t.integer :item_id
      t.integer :value
      t.text :desc

      t.timestamps
    end
    add_index :statistics, [:name, :item_id]
  end

  def down
    drop_table :statistics
  end
end

1 Comment

that's exactly what I said in my answer
3

If you have more than one index and don't want to repeat the table name several times in individual add_index calls, you can use a change_table block that follows the create_table.

create_table :user_states do |t|
  t.references :user, :null => false
  t.integer :rank
  t.integer :status_code
end

change_table :user_states do |t|
  t.index [:rank, :status_code]
end

Comments

2
    class CreateTempPfp < ActiveRecord::Migration
      def change
        create_table :temp_ptps do |t|
          t.string :owner
          t.integer :source_id
          t.string :source_type
          t.integer :year
          t.string :pcb_type
          t.float :january
          t.float :february
          t.float :march
          t.float :april
          t.float :may
          t.float :june
          t.float :july
          t.float :august
          t.float :september
          t.float :october
          t.float :november
          t.float :december
          t.float :dollar_per_sqft
          t.float :dollar_per_unit
          t.integer :rp_acc_code
          t.integer :rp_property_id
          t.integer :real_estate_property_id
          t.timestamps
       end
       add_index :temp_ptps, [:source_id, :source_type]
     end
   end

Comments

1

It looks like create_table yields an ActiveRecord::ConnectionAdapters::TableDefinition class. This class does not contain the method index. Instead, change_table appears to yield an ActiveRecord::ConnectionAdapters::Table class which includes this index method.

If you want to add an index during a create_table migration, try this:

class CreateStatistics < ActiveRecord::Migration
  def self.up
    create_table :statistics do |t|
      t.string :name
      t.integer :item_id
      t.integer :value
      t.text :desc

      t.timestamps
    end

    add_index :statistics, :name
    add_index :statistics, :item_id
  end

  def self.down
    drop_table :statistics
  end
end

1 Comment

use add_index :table_name, ... outside of your create_table call

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.