Rails: добавление индекса после добавления столбца


119

Предположим, я создал таблицу tableв приложении Rails. Некоторое время спустя добавляю столбец, работающий:

rails generate migration AddUser_idColumnToTable user_id:string. 

Затем я понимаю, что мне нужно добавить user_idв качестве индекса. Я знаю о add_indexметоде, но где его вызывать? Должен ли я выполнить миграцию (если да, какую?), А затем добавить вручную этот метод?

Ответы:


235

Вы можете запустить еще одну миграцию только для индекса:

class AddIndexToTable < ActiveRecord::Migration
  def change
    add_index :table, :user_id
  end
end

4
Поэтому я просто запускаю в своей консоли: rails generate migration AddIndexToTable?
user1611830 08

3
Да, вы можете это сделать, но впоследствии вам придется отредактировать эту миграцию, чтобы отразить приведенный выше код.
Яап Хаагманс

Предполагается, что: таблица должна быть множественного числа?
гробница

1
@tomb Я использовал пример из исходного вопроса. :tableэто фактическое имя таблицы, так и в случае usersтаблицы, нужно заменить :usersна :table.
Яап Хаагманс

65

Если вам нужно создать, user_idтогда будет разумным предположить, что вы ссылаетесь на пользовательскую таблицу. В этом случае миграция должна быть:

rails generate migration AddUserRefToProducts user:references

Эта команда сгенерирует следующую миграцию:

class AddUserRefToProducts < ActiveRecord::Migration
  def change
    add_reference :user, :product, index: true
  end
end

После запуска rake db:migrateодновременно user_idстолбца и индекс будет добавлен к productsтаблице.

Если вам просто нужно добавить индекс к существующему столбцу, например, nameк userтаблице, может оказаться полезным следующий прием:

rails generate migration AddIndexToUsers name:string:index сгенерирует следующую миграцию:

class AddIndexToUsers < ActiveRecord::Migration
  def change
    add_column :users, :name, :string
    add_index :users, :name
  end
end

Удалите add_columnстроку и запустите миграцию.

В описанном случае вы могли ввести rails generate migration AddIndexIdToTable index_id:integer:indexкоманду, а затем удалить add_columnстроку из сгенерированной миграции. Но я бы рекомендовал отменить первоначальную миграцию и вместо этого добавить ссылку:

rails generate migration RemoveUserIdFromProducts user_id:integer
rails generate migration AddUserRefToProducts user:references

Спасибо Вадиму за исчерпывающий ответ. И последний вопрос: почему вы порекомендуете отменить первоначальную миграцию? Есть ли проблемы с производительностью, связанные с добавлением индекса позже?
Флавио Венше

2
К @fwuensche: добавление индекса в дальнейшем не снижает производительности. Однако логика предметной области будет менее ясной. Например, если вы позже решите разорвать / абстрагировать / и т. Д. Эту ассоциацию, вам придется иметь дело с двумя отдельными миграциями, которые на самом деле должны были быть одной ...
Вадим Тимиров 01

6
ВНИМАНИЕ: обратите внимание, что index: true работает только при миграции create_table. Перенос будет запущен, но индекс не будет создан. См. Makandracards.com/makandra/…
rmcsharry

9

Добавьте в сгенерированную миграцию после создания столбца следующее (пример)

add_index :photographers, :email, :unique => true

вы имеете в виду что-то вроде этого: def self.up add_column ... end add_index ...?
user1611830 08

6

Для справок вы можете позвонить

rails generate migration AddUserIdColumnToTable user:references

Если в будущем вам понадобится добавить общий индекс, вы можете запустить этот

rails g migration AddOrdinationNumberToTable ordination_number:integer:index

Сгенерировать код:

class AddOrdinationNumberToTable < ActiveRecord::Migration
  def change
   add_column :tables, :ordination_number, :integer
   add_index :tables, :ordination_number, unique: true
  end
end

0

Вы можете использовать это, просто подумайте, что Job - это имя модели, к которой вы добавляете индекс cader_id :

class AddCaderIdToJob < ActiveRecord::Migration[5.2]
  def change
    change_table :jobs do |t|
      t.integer :cader_id
      t.index :cader_id
    end
  end
end
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.