Rails: aggiunta di un indice dopo l'aggiunta di una colonna


119

Supponiamo di aver creato una tabella tablein un'app Rails. Qualche tempo dopo, aggiungo una colonna che esegue:

rails generate migration AddUser_idColumnToTable user_id:string. 

Poi mi rendo conto che devo aggiungere user_idcome indice. Conosco il add_indexmetodo, ma dove dovrebbe essere chiamato questo metodo? Dovrei eseguire una migrazione (se sì, quale?), Quindi aggiungendo manualmente questo metodo?

Risposte:


235

Puoi eseguire un'altra migrazione, solo per l'indice:

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

4
Quindi corro semplicemente nella mia console: rails genera la migrazione AddIndexToTable?
user1611830

3
Sì, puoi farlo, ma dovrai modificare la migrazione in seguito per riflettere il codice sopra.
Jaap Haagmans

La tabella dovrebbe essere plurale?
tomba

1
@tomb Ho usato l'esempio della domanda originale. :tableè il nome della tabella effettiva, così nel caso di un userstavolo, devi sostituire :usersper :table.
Jaap Haagmans

65

Se è necessario creare un user_id, sarebbe ragionevole presumere che si faccia riferimento a una tabella utente. In tal caso la migrazione sarà:

rails generate migration AddUserRefToProducts user:references

Questo comando genererà la seguente migrazione:

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

Dopo aver eseguito rake db:migratesia una user_idcolonna che un indice verranno aggiunti alla productstabella.

Nel caso in cui sia necessario aggiungere un indice a una colonna esistente, ad esempio nameuna usertabella, la seguente tecnica può essere utile:

rails generate migration AddIndexToUsers name:string:index genererà la seguente migrazione:

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

Elimina la add_columnriga ed esegui la migrazione.

Nel caso descritto avresti potuto emettere il rails generate migration AddIndexIdToTable index_id:integer:indexcomando e poi cancellare la add_columnriga dalla migrazione generata. Ma preferirei piuttosto annullare la migrazione iniziale e aggiungere invece il riferimento:

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

Grazie Vadym per la risposta completa. Un'ultima domanda: perché consiglieresti di annullare la migrazione iniziale? C'è qualche problema di prestazioni relativo all'aggiunta successiva dell'indice?
Flavio Wuensche

2
A @fwuensche: non è prevista alcuna penalizzazione delle prestazioni per l'aggiunta successiva dell'indice. La logica del dominio sarà però meno chiara. Ad esempio, nel caso in cui decidessi di interrompere / astrarre / ecc. L'associazione in un secondo momento, avresti dovuto
occuparti di

6
ATTENZIONE: nota che index: true funziona solo in una migrazione create_table. La migrazione verrà eseguita, ma non verrà creato alcun indice. Vedi makandracards.com/makandra/…
rmcsharry

9

Aggiungere nella migrazione generata dopo aver creato la colonna quanto segue (esempio)

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

vuoi dire qualcosa del genere: def self.up add_column ... end add_index ...?
user1611830

5

Per referenze puoi chiamare

rails generate migration AddUserIdColumnToTable user:references

Se in futuro è necessario aggiungere un indice generale, è possibile avviarlo

rails g migration AddOrdinationNumberToTable ordination_number:integer:index

Genera codice:

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

0

Puoi usarlo, pensa che Job è il nome del modello a cui stai aggiungendo l'indice 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.