Specificare il nome della colonna in una migrazione "riferimenti"


124

Voglio creare un migrationin Rails, facendo riferimento a un'altra tabella. Di solito, farei qualcosa come:

add_column :post, :user, :references

Questo crea una colonna denominata user_idin poststable. Ma cosa succede se, invece di user_id, voglio qualcosa di simile author_id? Come lo posso fare?

Risposte:


59

Fallo manualmente:

add_column :post, :author_id, :integer

ma ora, quando crei l'istruzione appartiene_to, dovrai modificarla, quindi ora devi chiamare

def post
    belongs_to :user, :foreign_key => 'author_id'
end

1
Non devo aggiungere alcun indice?
caarlos0

1
Sì, dovrai creare un indice nella migrazione.
Tom Harrison

1
Trucchi di Rails: in realtà non usa gli indici per impostazione predefinita. Ora, se vuoi gli indici (che sono un'ottima idea, nonostante il fatto che rails li ignorerà completamente), puoi certamente aggiungerli. Ti consigliamo di consultare la guida che collegamento per ulteriori informazioni sulle migrazioni in generale e potresti persino finire per inserire il codice SQL chiamando direttamente nella migrazione. Direi di ignorarlo, poiché non è una parte normale di rails, ne otterrai 0 prestazioni, poiché le query SQL generate di default da rails non ne traggono vantaggio. link
mschultz

hmm capito. Grazie mille!
caarlos0

usando schema_plusgem, t.references :category, index: true, foreign_key: true, references: :match_categoriesha funzionato anche per me nel file di migrazione.
elquimista

251

Per Rails 5+

Definizione iniziale:

Se si definisce la vostra Posttabella di modello, è possibile impostare references, indexe foreign_keyin una sola riga:

t.references :author, index: true, foreign_key: { to_table: :users }

Aggiorna esistente:

Se stai aggiungendo riferimenti a una tabella esistente, puoi farlo:

add_reference :posts, :author, foreign_key: { to_table: :users }

Nota: il valore predefinito per indexè true.


La definizione iniziale consentirà i valori nulli? In caso contrario, conosci l'alternativa nullable?
Vorpulus Lyphane

5
Questa definizione consente nulls. Per non consentirli, aggiungi la solita opzione null: false.
Ashitaka

Grazie. Per la "definizione iniziale", penso che "index: true" non sia necessario. Ottengo lo stesso cambio di schema con o senza di esso. Non importa; ho appena visto la tua nota alla fine.
Joey

Grazie, questo è quello che stavo cercando!
Philippe B.

250

In Rails 4.2+ puoi anche impostare chiavi esterne nel db, il che è un'ottima idea .

Per associazioni semplici questo può essere fatto anche t.referencesaggiungendo foreign_key: true, ma in questo caso avrai bisogno di due righe.

# The migration
add_reference :posts, :author, index: true
add_foreign_key :posts, :users, column: :author_id

# The model
belongs_to :author, class_name: "User"

2
Grazie, ma la domanda è etichettata Rails3, sono felice di dare una mano
ecoologic

2
Ooh, non l'ho notato. Bene, è stato molto utile a me. :)
bonh

2
Avevo quasi perso la speranza quando l'ho visto! Grazie @ecoologic!
Dan Williams

2
@ecoologic, solo una cosa che potresti voler aggiungere, add_foreign_key è solo rails 4.2+. ;)
Dan Williams

4
Non sono sicuro che tu abbia bisogno references: :usersdell'opzione nella add_referencechiamata. Non lo vedo documentato nei documenti e sembra funzionare dalla mia parte senza di esso.
jakecraige

87

In rails 4, quando usi postgresql e schema_plus gem puoi semplicemente scrivere

add_reference :posts, :author, references: :users

Questo creerà una colonna author_id, che fa correttamente riferimento ausers(id) .

E nel tuo modello scrivi

belongs_to :author, class_name: "User"

Nota, quando crei una nuova tabella puoi scriverla come segue:

create_table :things do |t| 
  t.belongs_to :author, references: :users 
end 

Nota: la schema_plusgem nella sua interezza non è compatibile con rails 5+, ma questa funzionalità è offerta da gem schema_auto_foreign_keys (parte di schema_plus) che è compatibile con rails 5.


28
e se stai usando create_table:t.references :author, references: :users
Michael Radionov

2
Aggiungere il commento di @ MichaelRadionov alla tua risposta lo renderebbe perfetto.
toxaq

2
Ho esaminato il sorgente Rails 4.1 e non riesco a trovare alcuna prova che :referenceseffettivamente faccia qualcosa.
jes5199

1
Sì, hai ragione, ho usato la schema_plusgemma per anni e in realtà sta aggiungendo quella funzionalità. Ho modificato la mia risposta di conseguenza.
nathanvda

2
In Rails 6, sembra che la sintassi funzioni t.references :col_name, references: other_table_namesenza installare gemme aggiuntive.
Qqwy

51

Se non stai utilizzando una chiave esterna, non importa quale sia il nome effettivo della tabella dell'altra tabella.

add_reference :posts, :author

A partire da Rails 5 , se stai usando una chiave esterna, puoi specificare il nome dell'altra tabella nelle opzioni della chiave esterna. (vedi https://github.com/rails/rails/issues/21563 per la discussione)

add_reference :posts, :author, foreign_key: {to_table: :users}

Prima di Rails 5, dovresti aggiungere la chiave esterna come passaggio separato:

add_foreign_key :posts, :users, column: :author_id

12
to_table è la forma pluralizzata:{to_table: :users}
hoffmanc

-3

alias_attribute (new_name, old_name) è molto utile. Basta creare il tuo modello e la relazione:

rails g model Post title user:references

quindi modificare il modello e aggiungere un alias di attributo con

alias_attribute :author, :user

Dopodiché sarai in grado di eseguire cose come

Post.new(title: 'My beautiful story', author: User.first)

1
questo non funziona quando è necessario definire più riferimenti a un altro modello, ad esempio, post (autore, editore)
ultrajohn
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.