Spécification du nom de colonne dans une migration de «références»

124

Je veux faire un migrationdans Rails, référençant une autre table. Habituellement, je ferais quelque chose comme:

add_column :post, :user, :references

Cela crée une colonne nommée user_iddans la poststable. Mais que faire si, au lieu de user_id, je veux quelque chose comme author_id? Comment puis je faire ça?

caarlos0
la source

Réponses:

59

Faites-le manuellement:

add_column :post, :author_id, :integer

mais maintenant, lorsque vous créez l'instruction appartient_to, vous devrez la modifier, donc maintenant vous devez appeler

def post
    belongs_to :user, :foreign_key => 'author_id'
end
mschultz
la source
1
Ne dois-je pas ajouter d'index?
caarlos0
1
Oui, vous devrez créer un index lors de la migration.
Tom Harrison
1
Rails triche - il n'utilise pas vraiment d'index par défaut. Maintenant, si vous voulez des index (ce qui est une excellente idée - malgré le fait que les rails les ignorent complètement), vous pouvez certainement les ajouter. Vous voudrez consulter le guide que je lie pour plus d'informations sur les migrations en général, et vous pouvez même finir par mettre le code SQL d'appel directement dans votre migration. Je dirais de l'ignorer, car ce n'est pas une partie normale des rails, vous en obtiendrez 0 performance, car les requêtes SQL générées par défaut par les rails n'en tirent aucun avantage. lien
mschultz
hmm compris. Merci beaucoup!
caarlos0
en utilisant schema_plusgem, a t.references :category, index: true, foreign_key: true, references: :match_categorieségalement fonctionné pour moi dans le fichier de migration.
elquimista
251

Pour Rails 5+

Définition initiale:

Si vous définissez votre Posttable modèle, vous pouvez définir references, indexet foreign_keysur une seule ligne:

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

Mettre à jour existant:

Si vous ajoutez des références à une table existante, vous pouvez le faire:

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

Remarque: la valeur par défaut de indexest true.

Sheharyar
la source
La définition initiale autorisera-t-elle les valeurs nulles? Sinon, connaissez-vous l'alternative nullable?
Vorpulus Lyphane
5
Cette définition permet à l' nullart. Pour ne pas les autoriser, ajoutez l'option habituelle null: false.
Ashitaka
Merci. Pour la "Définition initiale", je pense que le "index: vrai" n'est pas nécessaire. J'obtiens le même changement de schéma avec ou sans lui. Ça ne fait rien; je viens de voir votre note à la fin.
Joey
Merci, c'est ce que je cherchais!
Philippe B.
250

Dans Rails 4.2+, vous pouvez également définir des clés étrangères dans la base de données, ce qui est une excellente idée .

Pour les associations simples, cela peut être fait également en t.referencesajoutant foreign_key: true, mais dans ce cas, vous aurez besoin de deux lignes.

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

# The model
belongs_to :author, class_name: "User"
écoologique
la source
2
Merci, mais la question est étiquetée Rails3, je suis heureux de vous aider
ecoologic
2
Ooh, je n'ai pas remarqué ça. Eh bien, cela a été très utile pour moi. :)
bonh
2
J'avais presque perdu espoir en voyant ça! Merci @ecoologic!
Dan Williams
2
@ecoologic, juste une chose que vous voudrez peut-être ajouter, add_foreign_key ne concerne que les rails 4.2+. ;)
Dan Williams
4
Je ne suis pas sûr que vous ayez besoin de l' references: :usersoption dans l' add_referenceappel. Je ne le vois pas documenté dans la documentation et il semble fonctionner de mon côté sans cela.
jakecraige
87

Dans les rails 4, lorsque vous utilisez postgresql et le gem schema_plus, vous pouvez simplement écrire

add_reference :posts, :author, references: :users

Cela créera une colonne author_id, qui fait correctement référence à users(id).

Et dans votre modèle, vous écrivez

belongs_to :author, class_name: "User"

Notez que lors de la création d'une nouvelle table, vous pouvez l'écrire comme suit:

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

Remarque: le schema_plusgem dans son intégralité n'est pas compatible avec les rails 5+, mais cette fonctionnalité est offerte par le gem schema_auto_foreign_keys (qui fait partie de schema_plus) qui est compatible avec les rails 5.

nathanvda
la source
28
et si vous utilisez create_table:t.references :author, references: :users
Michael Radionov
2
Ajouter le commentaire de @ MichaelRadionov à votre réponse la rendrait parfaite.
toxaq
2
J'ai regardé la source Rails 4.1, et je ne trouve aucune preuve qui :referencesfasse quoi que ce soit.
jes5199
1
Oui, vous avez raison, j'utilise le schema_plusbijou depuis des lustres et il ajoute en fait cette fonctionnalité. J'ai modifié ma réponse en conséquence.
nathanvda
2
Dans Rails 6, il semble que la syntaxe t.references :col_name, references: other_table_namefonctionne sans installer de gemmes supplémentaires.
Qqwy
51

Si vous n'utilisez pas de clé étrangère, le nom réel de la table de l'autre table n'a pas d'importance.

add_reference :posts, :author

À partir de Rails 5 , si vous utilisez une clé étrangère, vous pouvez spécifier le nom de l'autre table dans les options de clé étrangère. (voir https://github.com/rails/rails/issues/21563 pour discussion)

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

Avant Rails 5, vous devez ajouter la clé étrangère en tant qu'étape distincte:

add_foreign_key :posts, :users, column: :author_id
jes5199
la source
12
to_table est la forme pluralisée:{to_table: :users}
hoffmanc
-3

alias_attribute (nouveau_nom, ancien_nom) est très pratique. Créez simplement votre modèle et la relation:

rails g model Post title user:references

puis éditez le modèle et ajoutez un alias d'attribut avec

alias_attribute :author, :user

Après cela, vous pourrez exécuter des choses comme

Post.new(title: 'My beautiful story', author: User.first)
sekmo
la source
1
cela ne fonctionne pas lorsque vous avez besoin de définir plusieurs références à un autre modèle, par exemple, post (auteur, éditeur)
ultrajohn