Rails: Dodanie indeksu po dodaniu kolumny

119

Załóżmy, że utworzyłem tabelę tablew aplikacji Rails. Jakiś czas później dodaję kolumnę działającą:

rails generate migration AddUser_idColumnToTable user_id:string. 

Wtedy zdaję sobie sprawę, że muszę dodać user_idjako indeks. Wiem o tej add_indexmetodzie, ale gdzie należy ją wywołać? Czy mam uruchomić migrację (jeśli tak, którą?), A następnie ręcznie dodać tę metodę?

user1611830
źródło

Odpowiedzi:

235

Możesz przeprowadzić kolejną migrację, tylko dla indeksu:

class AddIndexToTable < ActiveRecord::Migration
  def change
    add_index :table, :user_id
  end
end
Jaap Haagmans
źródło
4
Więc po prostu uruchamiam w mojej konsoli: railsy generują migrację AddIndexToTable?
user1611830
3
Tak, możesz to zrobić, ale później będziesz musiał edytować tę migrację, aby odzwierciedlić powyższy kod.
Jaap Haagmans
Czy: tabela powinna być liczbą mnogą?
grób
1
@tomb Użyłem przykładu z oryginalnego pytania. :tablejest rzeczywista nazwa tabeli, więc w przypadku userstabeli, można zastąpić :usersprzez :table.
Jaap Haagmans
65

Jeśli chcesz utworzyć user_idtabelę, rozsądne byłoby założenie, że odwołujesz się do tabeli użytkownika. W takim przypadku migracja będzie:

rails generate migration AddUserRefToProducts user:references

To polecenie wygeneruje następującą migrację:

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

Po uruchomieniu rake db:migratezarówno user_idkolumna, jak i indeks zostaną dodane do productstabeli.

W przypadku wystarczy dodać indeks do istniejącej kolumny, na przykład namez usertabeli, następujące techniki mogą być pomocne:

rails generate migration AddIndexToUsers name:string:index wygeneruje następującą migrację:

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

Usuń add_columnlinię i uruchom migrację.

W opisanym przypadku można było wydać rails generate migration AddIndexIdToTable index_id:integer:indexpolecenie, a następnie usunąć add_columnwiersz z wygenerowanej migracji. Ale wolałbym raczej cofnąć początkową migrację i zamiast tego dodać odwołanie:

rails generate migration RemoveUserIdFromProducts user_id:integer
rails generate migration AddUserRefToProducts user:references
Vadym Tyemirov
źródło
Dzięki Vadym za pełną odpowiedź. Ostatnie pytanie: dlaczego poleciłbyś cofnąć początkową migrację? Czy jest jakiś problem z wydajnością związany z późniejszym dodaniem indeksu?
Flavio Wuensche
2
Do @fwuensche: nie ma spadku wydajności w przypadku późniejszego dodania indeksu. Jednak logika domeny będzie mniej jasna. Np. W przypadku, gdy później zdecydujesz się zerwać / wyodrębnić / itp. Powiązanie, musiałbyś mieć do czynienia z dwiema oddzielnymi migracjami, które naprawdę powinny być jedną ...
Vadym Tyemirov
6
OSTRZEŻENIE: Zwróć uwagę, że index: true działa tylko podczas migracji create_table. Migracja zostanie uruchomiona, ale nie zostanie utworzony żaden indeks. Zobacz makandracards.com/makandra/…
rmcsharry
9

Dodaj w wygenerowanej migracji po utworzeniu kolumny następujący (przykład)

add_index :photographers, :email, :unique => true
rdeandrade
źródło
masz na myśli coś takiego: def self.up add_column ... end add_index ...?
user1611830
5

Aby uzyskać referencje, możesz zadzwonić

rails generate migration AddUserIdColumnToTable user:references

Jeśli w przyszłości będziesz musiał dodać indeks ogólny, możesz go uruchomić

rails g migration AddOrdinationNumberToTable ordination_number:integer:index

Wygeneruj kod:

class AddOrdinationNumberToTable < ActiveRecord::Migration
  def change
   add_column :tables, :ordination_number, :integer
   add_index :tables, :ordination_number, unique: true
  end
end
Mauro
źródło
0

Możesz tego użyć, pomyśl tylko, że Job to nazwa modelu, do którego dodajesz indeks 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
vidur punj
źródło