Migrations Rails 3: Ajouter une colonne de référence?

162

Si je crée une nouvelle migration Rails 3 avec (par exemple)

rails g migration tester title:tester user:references

, tout fonctionne bien ... mais si j'ajoute une colonne avec quelque chose du genre:

rails g migration add_user_to_tester user:references

le champ de référence n'est pas reconnu. En bref, la question est: comment ajouter une colonne de référencement à une migration de rails à partir de la ligne de commande?

Plancton
la source

Réponses:

205

Si vous utilisez Rails 4.x, vous pouvez maintenant générer des migrations avec des références, comme ceci:

rails generate migration AddUserRefToProducts user:references

comme vous pouvez le voir sur les guides de rails

Paulo Fidalgo
la source
1
Voir la section 2.1 de edgeguides.rubyonrails.org/active_record_migrations.html par exemple.
B Seven
2
comment spécifier un nom de colonne pour la clé étrangère au lieu du nom généré automatiquement?
j
@jwill vous pouvez utiliser polymorphic: user: references {polymorphic}.
Paulo Fidalgo du
@PauloFidalgo Pouvez-vous expliquer un peu comment faire cela? peut être un guide de liens? (parle de polymorphe)
Anwar
@Anwar: voici la documentation api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/…
Paulo Fidalgo
186

EDIT : Ceci est une réponse obsolète et ne devrait pas être appliquée pour Rails 4.x +

Vous n'avez pas besoin d'ajouter des références lorsque vous pouvez utiliser un identifiant entier pour votre classe référencée.

Je dirais que l'avantage d'utiliser des références au lieu d'un entier simple est que le modèle sera prédéfini avec appartient_to et que le modèle est déjà créé et ne sera pas affecté lorsque vous migrez quelque chose d'existant, le but est en quelque sorte perdu.

Donc, je ferais comme ça à la place:

rails g migration add_user_id_to_tester user_id:integer

Et puis ajoutez manuellement appartient_to: utilisateur dans le modèle du testeur

DanneManne
la source
9
Mais cela ne créera pas les contraintes de clé étrangère appropriées sur les bases de données qui le prennent en charge, non?
abahgat
19
Non, afaik Rails ne crée jamais de restrictions de clé étrangère sur la base de données, sauf si vous ajoutez des plugins pour le faire à votre place.
DanneManne
juste étudier ce post, pls comment puis-je ajouter la référence après tout
El nino
13
n'oubliez pas d'ajouter l'index avec user: integer: index
rickypai
3
La réponse est datée, voir la réponse de @ Paulo pour les rails modernes.
OneHoopyFrood
102

Veuillez noter que vous aurez très probablement besoin d'un index sur cette colonne également.

class AddUserReferenceToTester < ActiveRecord::Migration
  def change
    add_column :testers, :user_id, :integer
    add_index  :testers, :user_id
  end
end
Eugène
la source
1
Pourquoi? Est-ce vrai pour la plupart des relations appartient_to?
ahnbizcad
C'est en effet pour des raisons de performances et est utile si vous avez un has_many / has_one de l'autre côté de la relation appart_to. Si vous êtes absolument sûr de ne pas passer, user.testersvous pouvez omettre l'index.
Eugene
1
Le rails g migration ...généré add_reference :installs, :device, index: truequi crée également l'index.
B Seven du
49

Avec les deux étapes précédentes indiquées ci-dessus, il vous manque toujours la contrainte de clé étrangère. Cela devrait fonctionner:

  class AddUserReferenceToTester < ActiveRecord::Migration
      def change
          add_column :testers, :user_id, :integer, references: :users
      end
  end
Martin Cabrera Diaubalick
la source
C'est la seule réponse réelle ici. La clé étrangère est la partie la plus critique ici
user2490003
cela doit être marqué comme la bonne réponse puisque les questions demandent des rails 3
Carlos Roque
35

Vous pouvez utiliser des références dans une migration de modification. Ceci est un code Rails 3.2.13 valide:

class AddUserToTester < ActiveRecord::Migration
  def change
    change_table :testers do |t|
      t.references :user, index: true 
    end
  end
  def down
    change_table :testers do |t|
      t.remove :user_id
    end
  end
end

cf: http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/change_table

gl03
la source
1
changer et abaisser les méthodes? ne sont pas des méthodes de haut en bas à la place?
MaicolBen
@MaicolBen oui, et vous pouvez également laisser la méthode down.
Hut8
@MaicolBen Sans la downméthode, j'ai obtenu ActiveRecord::IrreversibleMigrationlors de la restauration en utilisant Rails 3.2. J'ai également dû changer changepour up.
Andrew Grimm
27

L'exécution rails g migration AddUserRefToSponsors user:referencesgénérera la migration suivante:

def change
  add_reference :sponsors, :user, index: true
end
Wirwing
la source
À quelle version de Rails est-ce destiné?
Andrew Grimm
8

Lors de l'ajout d'une colonne, vous devez faire de cette colonne un entier et si possible vous en tenir aux conventions de rails. Donc, pour votre cas, je suppose que vous avez déjà un testeur et des modèles utilisateur, ainsi que des tables de testeurs et d'utilisateurs.

Pour ajouter la clé étrangère, vous devez créer une colonne entière avec le nom user_id (convention):

add_column :tester, :user_id, :integer

Ajoutez ensuite un appartient au modèle de testeur:

class Tester < ActiveRecord::Base
  belongs_to :user
end

Et vous pouvez également ajouter un index pour la clé étrangère (c'est quelque chose que les références font déjà pour vous):

add_index :tester, :user_id
Zamith
la source
8

Cela fera l'affaire:

rails g migration add_user_to_tester user_id:integer:index
magistralement
la source
J'aime le fait que cela ajoute également l'index que vous voudrez probablement.
bheeshmar
3

Vous pouvez ajouter des références à votre modèle via la ligne de commande de la manière suivante:

rails g migration add_column_to_tester user_id:integer

Cela générera un fichier de migration comme:

class AddColumnToTesters < ActiveRecord::Migration
  def change
    add_column :testers, :user_id, :integer
  end
end

Cela fonctionne bien chaque fois que je l'utilise.

Neha
la source
3

Pour Rails 4

Le générateur accepte le type de colonne comme référence (également disponible en tant que belongs_to).

Cette migration créera une user_idcolonne et un index approprié:

$ rails g migration AddUserRefToProducts user:references 

génère:

class AddUserRefToProducts < ActiveRecord::Migration
  def change
    add_reference :products, :user, index: true
  end
end

http://guides.rubyonrails.org/active_record_migrations.html#creating-a-standalone-migration

Pour Rails 3

Helper est appelé références (également disponible en tant que belongs_to).

Cette migration créera une category_idcolonne du type approprié. Notez que vous transmettez le nom du modèle et non le nom de la colonne. Active Record ajoute le _idpour vous.

change_table :products do |t|
  t.references :category
end

Si vous avez des belongs_toassociations polymorphes, les références ajouteront les deux colonnes requises:

change_table :products do |t|
  t.references :attachment, :polymorphic => {:default => 'Photo'}
end

Ajoutera une colonne attachment_id et une attachment_typecolonne de chaîne avec une valeur par défaut de Photo.

http://guides.rubyonrails.org/v3.2.21/migrations.html#creating-a-standalone-migration

Shilovk
la source