Aggiungi una migrazione della colonna di riferimento in Rails 4


311

Un utente ha molti caricamenti. Voglio aggiungere una colonna alla uploadstabella che fa riferimento a user. Come dovrebbe essere la migrazione?

Ecco quello che ho. Non sono sicuro se dovrei usare (1) :user_id, :into (2) :user, :references. Non sono nemmeno sicuro che (2) funzioni. Sto solo cercando di farlo nel modo "rotaie".

class AddUserToUploads < ActiveRecord::Migration
  def change
    add_column :uploads, :user_id, :integer
  end
end

Domanda pertinente ad eccezione delle migrazioni di Rails 3. Rails 3: aggiunta della colonna di riferimento?

Risposte:


707

Rotaie 4.x

Quando hai già users e uploadstabelle e desideri aggiungere una nuova relazione tra di loro.

Tutto quello che devi fare è: basta generare una migrazione usando il seguente comando:

rails g migration AddUserToUploads user:references

Che creerà un file di migrazione come:

class AddUserToUploads < ActiveRecord::Migration
  def change
    add_reference :uploads, :user, index: true
  end
end

Quindi, eseguire la migrazione utilizzando rake db:migrate. Questa migrazione si occuperà dell'aggiunta di una nuova colonna denominata user_idnella uploadstabella (facendo riferimento alla idcolonna nella userstabella), INOLTRE aggiungerà anche un indice sulla nuova colonna.

AGGIORNAMENTO [For Rails 4.2]

Non ci si può fidare delle rotaie per mantenere l'integrità referenziale; database relazionali vengono in nostro soccorso qui. Ciò significa che possiamo aggiungere vincoli di chiave esterna a livello del database stesso e garantire che il database respingerebbe qualsiasi operazione che viola questa serie integrità referenziale. Come ha commentato @infoget, Rails 4.2 viene fornito con supporto nativo per le chiavi esterne (integrità referenziale) . Non è richiesto ma potresti voler aggiungere una chiave esterna (poiché è molto utile) al riferimento che abbiamo creato sopra.

Per aggiungere una chiave esterna a un riferimento esistente , creare una nuova migrazione per aggiungere una chiave esterna:

class AddForeignKeyToUploads < ActiveRecord::Migration
  def change
    add_foreign_key :uploads, :users
  end
end

Per creare un riferimento completamente nuovo con una chiave esterna (in Rails 4.2) , generare una migrazione utilizzando il comando seguente:

rails g migration AddUserToUploads user:references

che creerà un file di migrazione come:

class AddUserToUploads < ActiveRecord::Migration
  def change
    add_reference :uploads, :user, index: true
    add_foreign_key :uploads, :users
  end
end

Ciò aggiungerà una nuova chiave esterna alla user_idcolonna della uploadstabella. La chiave fa riferimento alla idcolonna nella userstabella.

NOTA: questo è in aggiunta all'aggiunta di un riferimento, quindi è ancora necessario creare prima un riferimento, quindi una chiave esterna ( è possibile scegliere di creare una chiave esterna nella stessa migrazione o in un file di migrazione separato ). Attivo Record supporta solo a colonna singola chiavi esterne e attualmente solo mysql, mysql2e PostgreSQLsono supportati gli adattatori. Non provarlo con altri adattatori come sqlite3, ecc. Fare riferimento a Guide Rails: chiavi esterne per riferimento.


8
In molti casi è bene aggiungere anche una chiave esterna. add_foreign_key (Rails 4.2)
poerror

18
Credo che puoi fare tutto in una riga: add_reference: uploads,: user, index: true, foreign_key: true @KirtiThorat
user1801879

33
Ora, se si utilizza la sintassi del generatore speciale per le migrazioni, Rails 4.2 creerà automaticamente la migrazione corretta con vincoli di chiave esterna inclusi. rails g migration AddUserToUploads user:referencesproduce add_reference :uploads, :user, index: true, foreign_key: truenella migrazione appropriata.
jrhorn424,

10
Usa ...index: true, foreign_key: trueinvece o line add_foreign_key.
Washington Botelho,

2
Perché abbiamo bisogno di entrambi foreign_keye t.reference? Non è t.referencesostanzialmente equivalente a foriegn_key+ index?
geoboy,

189

Rotaie 5

È ancora possibile utilizzare questo comando per creare la migrazione:

rails g migration AddUserToUploads user:references

La migrazione sembra un po 'diversa rispetto a prima, ma funziona ancora:

class AddUserToUploads < ActiveRecord::Migration[5.0]
  def change
    add_reference :uploads, :user, foreign_key: true
  end
end

Si noti che non lo :userè:user_id


2
Per le classi distanziate dal nome, come Local::Userinvece di Userfare qualcosa di simile rails g migration AddLocalUserToUploads user:references.
Ka Mok,

3
questo aggiunge automaticamente:index
Saravanabalagi Ramachandran,

4
@Zeke Sì, esegui la migrazione e controlla il tuo schema, dovrebbe dire qualcosa del generet.index ["user_id"], name: "index_uploads_on_user_id", using: :btree
Mirror318

1
sì, ho ricevuto un errore "indice esistente" quando ho aggiunto manualmente add_index nella migrazione: P @ Mirror318
Saravanabalagi Ramachandran

2
Dovremmo anche aggiungere belongs_to :userin Uploadclasse, in modo che possiamo usare upload.userper ottenere l'istanza dell'utente.
Spirito

17

se ti piace un altro approccio alternativo con upe downmetodo prova questo:

  def up
    change_table :uploads do |t|
      t.references :user, index: true
    end
  end

  def down
    change_table :uploads do |t|
      t.remove_references :user, index: true
    end
  end

9

[Uso di Rails 5]

Genera migrazione:

rails generate migration add_user_reference_to_uploads user:references

Questo creerà il file di migrazione:

class AddUserReferenceToUploads < ActiveRecord::Migration[5.1]
  def change
    add_reference :uploads, :user, foreign_key: true
  end
end

Ora se osservi il file dello schema, vedrai che la tabella dei caricamenti contiene un nuovo campo. Qualcosa del tipo: t.bigint "user_id"o t.integer "user_id".

Migra il database:

rails db:migrate

1
Questa risposta sembra duplicare la risposta di @ Mirror318. Commenta la risposta sopra se pensi che manchi qualcosa. Grazie.
M. Habib,

8

Un'altra sintassi di fare la stessa cosa è:

rails g migration AddUserToUpload user:belongs_to

7

Giusto per documentare se qualcuno ha lo stesso problema ...

Nella mia situazione ho usato i :uuidcampi e le risposte sopra non funzionano nel mio caso, perché le rotaie 5 stanno creando una colonna usando :bigintinvece :uuid:

add_column :uploads, :user_id, :uuid
add_index :uploads, :user_id
add_foreign_key :uploads, :users

È anche molto più chiaro cosa sta succedendo. Ma sì, UUID dovrebbe essere standard ora.
hadees

2

Crea un file di migrazione

rails generate migration add_references_to_uploads user:references

Nome chiave esterna predefinito

Ciò creerebbe una colonna id_utente nella tabella dei caricamenti come chiave esterna

class AddReferencesToUploads < ActiveRecord::Migration[5.2]
  def change
    add_reference :uploads, :user, foreign_key: true
  end
end

modello utente:

class User < ApplicationRecord
  has_many :uploads
end

modello di upload:

class Upload < ApplicationRecord
  belongs_to :user
end

Personalizza il nome della chiave esterna:

add_reference :uploads, :author, references: :user, foreign_key: true

Ciò creerebbe una colonna author_id nelle tabelle dei caricamenti come chiave esterna.

modello utente:

class User < ApplicationRecord
  has_many :uploads, foreign_key: 'author_id'
end

modello di upload:

class Upload < ApplicationRecord
  belongs_to :user
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.