Come posso rendere unica una colonna e indicizzarla in una migrazione Ruby on Rails?


416

Vorrei fare una colonna unique nello script di migrazione di Ruby on Rails. Qual'è il miglior modo di farlo? C'è anche un modo per indicizzare una colonna in una tabella?

Vorrei imporre le uniquecolonne in un database invece di usarle :validate_uniqueness_of.

Risposte:


686

La risposta breve per le vecchie versioni di Rails (vedi altre risposte per Rails 4+):

add_index :table_name, :column_name, unique: true

Per indicizzare più colonne insieme, si passa una matrice di nomi di colonna anziché un singolo nome di colonna,

add_index :table_name, [:column_name_a, :column_name_b], unique: true

Se ottieni "nome indice ... è troppo lungo", puoi aggiungere name: "whatever"al metodo add_index per ridurre il nome.

Per un controllo accurato, esiste un executemetodo " " che esegue SQL diretto.

Questo è tutto!

Se lo stai facendo in sostituzione delle normali convalide del vecchio modello, controlla come funziona. La segnalazione degli errori all'utente non sarà probabilmente piacevole senza convalide a livello di modello. Puoi sempre fare entrambe le cose.


36
+1 per aver suggerito di continuare a utilizzare validates_uniqueness_of. La gestione degli errori è molto più pulita usando questo metodo per il costo di una singola query indicizzata. Suggerirei che faccia entrambe le cose
Steve Weet,

1
Ho provato che non sembra funzionare! Potrei inserire due record con il nome_colonna che ho definito unico! Sto usando Rails 2.3.4 e MySql qualche idea?
Tam,

Ho usato il tuo secondo suggerimento usando execute: esegui "ALTER TABLE Users ADD UNIQUE (email)" e funziona! non so perché il primo non sarebbe interessato a saperlo
Tam,

1
Se viene visualizzato un indexed columns are not uniqueerrore durante il tentativo di creare un indice univoco, è possibile che i dati nella tabella contengano già duplicati. Prova a rimuovere i dati duplicati ed eseguire nuovamente la migrazione.
Hartley Brody,

5
Se ottieni "nome indice ... è troppo lungo", puoi aggiungere , :name => "whatever"al add_indexmetodo per abbreviare il nome.
Rick Smith,

129

le rotaie generano la migrazione add_index_to_table_name nome_colonna: uniq

o

le rotaie generano migrazione add_column_name_to_table_name nome_colonna: stringa: uniq: indice

genera

class AddIndexToModerators < ActiveRecord::Migration
  def change
    add_column :moderators, :username, :string
    add_index :moderators, :username, unique: true
  end
end

Se stai aggiungendo un indice a una colonna esistente, rimuovi o commenta la add_columnriga o metti un segno di spunta

add_column :moderators, :username, :string unless column_exists? :moderators, :username

5
L'ho votato perché volevo il modulo da riga di comando. Ma è sciocco che aggiunge la colonna anche quando lo specifico add_index...e non add_column....
Tyler Collier,

1
Sì, forse nella prossima versione.
d.danailov,

49

Dato che questo non è stato ancora menzionato ma risponde alla domanda che ho avuto quando ho trovato questa pagina, puoi anche specificare che un indice dovrebbe essere unico quando lo aggiungi tramite t.referenceso t.belongs_to:

create_table :accounts do |t|
  t.references :user, index: { unique: true } # or t.belongs_to

  # other columns...
end

(almeno da Rails 4.2.7)


42

Se stai creando una nuova tabella, puoi utilizzare il collegamento incorporato:

  def change
    create_table :posts do |t|
      t.string :title, null: false, index: { unique: true }
      t.timestamps
    end
  end

14

Sto usando Rails 5 e le risposte sopra funzionano alla grande; ecco un altro modo che ha funzionato anche per me (il nome della tabella è :peoplee il nome della colonna è :email_address)

class AddIndexToEmailAddress < ActiveRecord::Migration[5.0]
  def change
    change_table :people do |t|
      t.index :email_address, unique: true
    end
  end
end

1

È possibile che si desideri aggiungere il nome per la chiave univoca poiché molte volte il nome della chiave univoca predefinita per rotaie può essere troppo lungo per cui il DB può generare l'errore.

Per aggiungere il nome per il tuo indice basta usare l' name:opzione. La query di migrazione potrebbe assomigliare a questa:

add_index :table_name, [:column_name_a, :column_name_b, ... :column_name_n], unique: true, name: 'my_custom_index_name'

Maggiori informazioni - http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/add_index


1
add_index :table_name, :column_name, unique: true

Per indicizzare più colonne insieme, si passa una matrice di nomi di colonna anziché un singolo nome di colonna.


0

Se hai perso l'aggiunta di univoco alla colonna DB, aggiungi questa convalida nel modello per verificare se il campo è univoco:

class Person < ActiveRecord::Base
  validates_uniqueness_of :user_name
end

fare riferimento qui sopra è solo a scopo di test, si prega di aggiungere indice modificando la colonna DB come suggerito da @Nate

si prega di fare riferimento a questo con l'indice per ulteriori informazioni


2
Non consiglierei solo di aggiungere la convalida senza un indice corrispondente. L'opzione migliore è pulire tutti i duplicati esistenti e quindi aggiungere l'indice. Altrimenti si rischia di invalidare i dati esistenti (il che provocherà il fallimento di eventuali aggiornamenti di tali righe) e si potrebbe comunque finire con duplicati se si dispone di un codice che salta le convalide di Rails. (ad esempio, quando si esegue un update_all o inserimenti SQL diretti)
Nate
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.