Fügen Sie in Rails 4 eine Referenzspaltenmigration hinzu

310

Ein Benutzer hat viele Uploads. Ich möchte der uploadsTabelle eine Spalte hinzufügen, die auf die verweist user. Wie soll die Migration aussehen?

Hier ist was ich habe. Ich bin mir nicht sicher, ob ich (1) :user_id, :intoder (2) verwenden soll :user, :references. Ich bin mir nicht mal sicher, ob (2) funktioniert. Ich versuche nur, dies auf die "Schienen" Weise zu tun.

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

Relevante Frage mit Ausnahme von Rails 3. Rails 3-Migrationen: Hinzufügen einer Referenzspalte?

Don P.
quelle

Antworten:

706

Schienen 4.x.

Wenn Sie bereits Tabellen habenusers und eine neue Beziehung zwischen ihnen hinzufügenuploads möchten .

Alles, was Sie tun müssen, ist: Generieren Sie einfach eine Migration mit dem folgenden Befehl:

rails g migration AddUserToUploads user:references

Welches erstellt eine Migrationsdatei als:

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

Führen Sie dann die Migration mit aus rake db:migrate. Diese Migration kümmert sich um eine neue Spalte hinzuzufügen Namen user_idzu uploadsTabelle (Referenzierung idSpalt in usersTabelle), PLUS wird es auch einen Index für die neue Spalte hinzuzufügen.

UPDATE [Für Schienen 4.2]

Rails kann nicht als vertrauenswürdig eingestuft werden, um die referenzielle Integrität aufrechtzuerhalten. Hier helfen uns relationale Datenbanken . Dies bedeutet, dass wir auf Datenbankebene selbst Fremdschlüsseleinschränkungen hinzufügen und sicherstellen können, dass die Datenbank alle Vorgänge ablehnt, die diese referenzielle Integrität verletzen. Wie @infoget kommentierte, wird Rails 4.2 mit nativer Unterstützung für Fremdschlüssel geliefert (referenzielle Integrität) . Es ist nicht erforderlich, aber Sie möchten möglicherweise einen Fremdschlüssel (da dies sehr nützlich ist) zu der oben erstellten Referenz hinzufügen.

Um einer vorhandenen Referenz einen Fremdschlüssel hinzuzufügen, erstellen Sie eine neue Migration, um einen Fremdschlüssel hinzuzufügen:

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

Um eine völlig neue Referenz mit einem Fremdschlüssel (in Rails 4.2) zu erstellen , generieren Sie eine Migration mit dem folgenden Befehl:

rails g migration AddUserToUploads user:references

Dadurch wird eine Migrationsdatei erstellt als:

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

Dadurch wird der user_idSpalte der uploadsTabelle ein neuer Fremdschlüssel hinzugefügt . Der Schlüssel verweist auf die idSpalte in der usersTabelle.

HINWEIS: Dies ist zusätzlich zum Hinzufügen einer Referenz erforderlich, sodass Sie zuerst eine Referenz und dann einen Fremdschlüssel erstellen müssen ( Sie können wählen, ob Sie einen Fremdschlüssel in derselben Migration oder in einer separaten Migrationsdatei erstellen möchten ). Active Record unterstützt nur einzelne Spalte Fremdschlüssel und zur Zeit nur mysql, mysql2und PostgreSQLAdapter werden unterstützt. Versuchen Sie dies nicht mit anderen Adaptern wie sqlite3usw. Siehe Rails Guides: Foreign Keys als Referenz.

Kirti Thorat
quelle
8
In vielen Fällen ist es auch gut, Fremdschlüssel hinzuzufügen. add_foreign_key (Rails 4.2)
poerror
18
Ich glaube, Sie können alles in einer Zeile tun: add_reference: uploads ,: user, index: true, Foreign_key: true @KirtiThorat
user1801879
32
Wenn Sie jetzt die spezielle Generatorsyntax für Migrationen verwenden, erstellt Rails 4.2 automatisch die richtige Migration mit Fremdschlüsseleinschränkungen. rails g migration AddUserToUploads user:referenceserzeugt add_reference :uploads, :user, index: true, foreign_key: truein der entsprechenden Migration.
jrhorn424
10
Verwenden Sie ...index: true, foreign_key: truestattdessen o line add_foreign_key.
Washington Botelho
2
Warum brauchen wir beide foreign_keyund t.reference? Ist nicht im t.referenceWesentlichen gleichbedeutend mit foriegn_key+ index?
Geoboy
188

Schienen 5

Mit diesem Befehl können Sie weiterhin die Migration erstellen:

rails g migration AddUserToUploads user:references

Die Migration sieht etwas anders aus als zuvor, funktioniert aber immer noch:

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

Beachten Sie :user, dass dies nicht der Fall ist:user_id

Mirror318
quelle
2
Für Klassen mit Namensabständen, Local::Useranstatt Useretwas zu tun rails g migration AddLocalUserToUploads user:references.
Ka Mok
3
fügt dies automatisch hinzu:index
Saravanabalagi Ramachandran
4
@Zeke Ja, führen Sie die Migration aus und überprüfen Sie Ihr Schema, es sollte so etwas wiet.index ["user_id"], name: "index_uploads_on_user_id", using: :btree
Mirror318
1
Ja, ich habe den Fehler "Index existiert" erhalten, als ich den add_index bei der Migration manuell hinzugefügt habe: P @ Mirror318
Saravanabalagi Ramachandran
2
Wir sollten auch hinzufügen , belongs_to :userin der UploadKlasse, so können wir verwenden upload.userdie Benutzerinstanz zu lernen.
Wit
17

Wenn Sie einen anderen alternativen Ansatz mit upund downMethode mögen , versuchen Sie Folgendes:

  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
Kiry Meas
quelle
9

[Verwenden von Schienen 5]

Migration generieren:

rails generate migration add_user_reference_to_uploads user:references

Dadurch wird die Migrationsdatei erstellt:

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

Wenn Sie nun die Schemadatei beobachten, sehen Sie, dass die Upload-Tabelle ein neues Feld enthält. So etwas wie: t.bigint "user_id"oder t.integer "user_id".

Datenbank migrieren:

rails db:migrate
vantony
quelle
1
Diese Antwort scheint ein Duplikat der Antwort von @ Mirror318 zu sein. Bitte kommentieren Sie die obige Antwort, wenn Sie der Meinung sind, dass etwas darin fehlt. Vielen Dank.
M. Habib
8

Eine andere Syntax, um dasselbe zu tun, lautet:

rails g migration AddUserToUpload user:belongs_to
Nadeem Yasin
quelle
7

Nur um zu dokumentieren, ob jemand das gleiche Problem hat ...

In meiner Situation habe ich :uuidFelder verwendet, und die obigen Antworten funktionieren in meinem Fall nicht, da Schienen 5 :bigintstattdessen eine Spalte mit folgenden Elementen erstellen :uuid:

add_column :uploads, :user_id, :uuid
add_index :uploads, :user_id
add_foreign_key :uploads, :users
Bruno Casali
quelle
Es ist auch viel klarer, was passiert. Aber ja, UUID sollte jetzt Standard sein.
hadees
2

Erstellen Sie eine Migrationsdatei

rails generate migration add_references_to_uploads user:references

Standard-Fremdschlüsselname

Dies würde eine user_id-Spalte in der Upload-Tabelle als Fremdschlüssel erstellen

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

Benutzermodell:

class User < ApplicationRecord
  has_many :uploads
end

Modell hochladen:

class Upload < ApplicationRecord
  belongs_to :user
end

Anpassen des Fremdschlüsselnamens:

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

Dies würde eine author_id-Spalte in den Upload-Tabellen als Fremdschlüssel erstellen.

Benutzermodell:

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

Modell hochladen:

class Upload < ApplicationRecord
  belongs_to :user
end
Clint Clinton
quelle