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?

mu is too short
  • 426,620
  • 70
  • 833
  • 800
linjunhalida
  • 4,538
  • 6
  • 44
  • 64

5 Answers5

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.

Brandan
  • 14,735
  • 3
  • 56
  • 71
  • 1
    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. – Tom Harrison Apr 27 '12 at 14:04
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
linjunhalida
  • 4,538
  • 6
  • 44
  • 64
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
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
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
Lee Jarvis
  • 16,031
  • 4
  • 38
  • 40