Ajouter une migration de colonne de référence dans Rails 4

311

Un utilisateur a de nombreux téléchargements. Je veux ajouter une colonne au uploadstableau qui référence le user. À quoi devrait ressembler la migration?

Voici ce que j'ai. Je ne sais pas si je dois utiliser (1) :user_id, :intou (2) :user, :references. Je ne sais même pas si (2) fonctionne. J'essaye juste de faire ça de la manière des "rails".

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

Question pertinente sauf pour Rails 3. Migrations Rails 3: Ajout d'une colonne de référence?

Don P
la source

Réponses:

707

Rails 4.x

Lorsque vous avez déjà users et les uploadstables et que vous souhaitez ajouter une nouvelle relation entre eux.

Tout ce que vous devez faire est de: générer simplement une migration à l'aide de la commande suivante:

rails g migration AddUserToUploads user:references

Ce qui créera un fichier de migration comme:

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

Exécutez ensuite la migration à l'aide de rake db:migrate. Cette migration se chargera d'ajouter une nouvelle colonne nommée user_idà la uploadstable (référençant la idcolonne dans la userstable), PLUS elle ajoutera également un index sur la nouvelle colonne.

MISE À JOUR [Pour Rails 4.2]

On ne peut pas faire confiance aux rails pour maintenir l'intégrité référentielle; les bases de données relationnelles viennent à notre secours ici. Cela signifie que nous pouvons ajouter des contraintes de clé étrangère au niveau de la base de données elle-même et garantir que la base de données rejettera toute opération qui viole cette intégrité référentielle définie. Comme l'a commenté @infoget, Rails 4.2 est livré avec une prise en charge native des clés étrangères (intégrité référentielle) . Ce n'est pas obligatoire mais vous voudrez peut-être ajouter une clé étrangère (car c'est très utile) à la référence que nous avons créée ci-dessus.

Pour ajouter une clé étrangère à une référence existante , créez une nouvelle migration pour ajouter une clé étrangère:

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

Pour créer une toute nouvelle référence avec une clé étrangère (dans Rails 4.2) , générez une migration à l'aide de la commande suivante:

rails g migration AddUserToUploads user:references

qui va créer un fichier de migration comme:

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

Cela ajoutera une nouvelle clé étrangère à la user_idcolonne de la uploadstable. La clé fait référence à la idcolonne du userstableau.

REMARQUE: cela s'ajoute à l'ajout d'une référence, vous devez donc toujours créer une référence, puis une clé étrangère ( vous pouvez choisir de créer une clé étrangère dans la même migration ou dans un fichier de migration distinct ). L'enregistrement actif prend uniquement en charge les clés étrangères à colonne unique et actuellement uniquement mysql, mysql2et les PostgreSQLadaptateurs sont pris en charge. N'essayez pas ceci avec d'autres adaptateurs comme sqlite3, etc. Référez-vous aux guides de rails: clés étrangères pour votre référence.

Kirti Thorat
la source
8
Dans de nombreux cas, il est également utile d'ajouter une clé étrangère. add_foreign_key (Rails 4.2)
poerror
18
Je pense que vous pouvez tout faire sur une seule ligne: add_reference: uploads,: user, index: true, foreign_key: true @KirtiThorat
user1801879
33
Maintenant, si vous utilisez la syntaxe spéciale du générateur pour les migrations, Rails 4.2 créera automatiquement la migration correcte avec les contraintes de clé étrangère incluses. rails g migration AddUserToUploads user:referencesproduit add_reference :uploads, :user, index: true, foreign_key: truedans la migration appropriée.
jrhorn424
10
Utilisez ...index: true, foreign_key: trueplutôt o line add_foreign_key.
Washington Botelho
2
Pourquoi avons-nous besoin des deux foreign_keyet t.reference? N'est-ce pas t.referenceessentiellement équivalent à foriegn_key+ index?
geoboy
189

Rails 5

Vous pouvez toujours utiliser cette commande pour créer la migration:

rails g migration AddUserToUploads user:references

La migration semble un peu différente de celle d'avant, mais fonctionne toujours:

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

Notez que ce n'est :userpas:user_id

Mirror318
la source
2
Pour les classes à espacement de noms, comme Local::Userau lieu de Userfaire quelque chose comme rails g migration AddLocalUserToUploads user:references.
Ka Mok
3
cela ajoute-t-il automatiquement:index
Saravanabalagi Ramachandran
4
@Zeke Oui, lancez la migration et vérifiez votre schéma, cela devrait dire quelque chose commet.index ["user_id"], name: "index_uploads_on_user_id", using: :btree
Mirror318
1
ouais, j'ai une erreur "index existe" quand j'ai ajouté manuellement l'add_index dans la migration: P @ Mirror318
Saravanabalagi Ramachandran
2
Nous devons également ajouter belongs_to :useren Uploadclasse, afin que nous puissions utiliser upload.userpour obtenir l'instance utilisateur.
Wit
17

si vous aimez une autre approche alternative avec upet downméthode essayez ceci:

  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
la source
9

[Utilisation de Rails 5]

Générez la migration:

rails generate migration add_user_reference_to_uploads user:references

Cela créera le fichier de migration:

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

Maintenant, si vous observez le fichier de schéma, vous verrez que la table des téléchargements contient un nouveau champ. Quelque chose comme: t.bigint "user_id"ou t.integer "user_id".

Migrer la base de données:

rails db:migrate
vantony
la source
1
Cette réponse semble être un double de la réponse de @ Mirror318. Veuillez commenter la réponse ci-dessus si vous pensez qu'il manque quelque chose. Merci.
M. Habib
8

Une autre syntaxe pour faire la même chose est:

rails g migration AddUserToUpload user:belongs_to
Nadeem Yasin
la source
7

Juste pour documenter si quelqu'un a le même problème ...

Dans ma situation, j'ai utilisé des :uuidchamps et les réponses ci-dessus ne fonctionnent pas dans mon cas, car les rails 5 créent une colonne en utilisant à la :bigintplace :uuid:

add_column :uploads, :user_id, :uuid
add_index :uploads, :user_id
add_foreign_key :uploads, :users
Bruno Casali
la source
C'est aussi beaucoup plus clair ce qui se passe. Mais oui, l'UUID devrait être standard maintenant.
hadees
2

Créer un fichier de migration

rails generate migration add_references_to_uploads user:references

Nom de clé étrangère par défaut

Cela créerait une colonne user_id dans la table des téléchargements en tant que clé étrangère

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

modèle d'utilisateur:

class User < ApplicationRecord
  has_many :uploads
end

modèle de téléchargement:

class Upload < ApplicationRecord
  belongs_to :user
end

Personnalisez le nom de la clé étrangère:

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

Cela créerait une colonne author_id dans les tables de téléchargement comme clé étrangère.

modèle d'utilisateur:

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

modèle de téléchargement:

class Upload < ApplicationRecord
  belongs_to :user
end
Clint Clinton
la source