web-dev-qa-db-fra.com

Rails Migration: add_reference to Table mais nom de colonne différent pour la clé étrangère que Rails Convention

J'ai les deux modèles suivants:

class Store < ActiveRecord::Base
    belongs_to :person
end

class Person < ActiveRecord::Base
    has_one :store
end

Voici le problème: J'essaie de créer une migration pour créer la clé étrangère dans la table des personnes. Cependant, la colonne faisant référence à la clé étrangère de Store n'est pas nommée store_id comme le serait Rails mais est à la place nommé foo_bar_store_id .

Si je suivais la convention Rails, je ferais la migration comme ceci:

class AddReferencesToPeople < ActiveRecord::Migration
  def change
    add_reference :people, :store, index: true
  end
end

Cependant, cela ne fonctionnera pas car le nom de la colonne n’est pas store_id mais foo_bar_store_id . Alors, comment puis-je spécifier que le nom de la clé étrangère est simplement différent, tout en conservant index: true pour maintenir des performances rapides?

51
Neil

EDIT: Pour ceux qui voient la tique et ne continuent pas à lire!

Bien que cette réponse atteigne l’objectif consistant à avoir un nom de colonne de clé étrangère non conventionnel, avec indexation, elle n’ajoute pas de contrainte fk à la base de données. Voir les autres réponses pour des solutions plus appropriées en utilisant add_foreign_key et/ou 'add_reference'.

Remarque: TOUJOURS regarder les autres réponses, celle acceptée n'est pas toujours la meilleure!

Réponse originale:

Dans votre migration AddReferencesToPeople, vous pouvez ajouter manuellement le champ et l'index en utilisant:

add_column :people, :foo_bar_store_id, :integer
add_index :people, :foo_bar_store_id

Et laissez ensuite votre modèle connaître la clé étrangère comme suit:

class Person < ActiveRecord::Base
  has_one :store, foreign_key: 'foo_bar_store_id'
end
6
Matt

Dans Rails 4.2, vous pouvez également configurer le modèle ou la migration avec un nom de clé étrangère personnalisé. Dans votre exemple, la migration serait la suivante:

class AddReferencesToPeople < ActiveRecord::Migration
  def change
    add_column :people, :foo_bar_store_id, :integer, index: true
    add_foreign_key :people, :stores, column: :foo_bar_store_id
  end
end

Here est un article de blog intéressant sur ce sujet. Ici est la section semi-cryptique des Rails Guides. Le billet de blog m'a définitivement aidé.

En ce qui concerne les associations, indiquez explicitement la clé étrangère ou le nom de la classe de la manière suivante (je pense que vos associations d'origine ont été permutées au fur et à mesure que la propriété 'Appartient à' dans la classe avec la clé étrangère):

class Store < ActiveRecord::Base
  has_one :person, foreign_key: :foo_bar_store_id
end

class Person < ActiveRecord::Base
  belongs_to :foo_bar_store, class_name: 'Store'
end

Notez que l'élément class_name doit être une chaîne. L'élément foreign_key peut être une chaîne ou un symbole. Ceci vous permet essentiellement d’accéder aux raccourcis astucieux d’ActiveRecord avec vos associations de nom sémantique, comme ceci:

person = Person.first
person.foo_bar_store
# returns the instance of store equal to person's foo_bar_store_id

En savoir plus sur les options d’association dans la documentation de appartient_to et has_one .

65
Sia

dans Rails 5.x, vous pouvez ajouter une clé étrangère à une table avec un nom différent, comme celui-ci:

class AddFooBarStoreToPeople < ActiveRecord::Migration[5.0]
  def change
    add_reference :people, :foo_bar_store, foreign_key: { to_table: :stores }
  end
end
65
schpet
# Migration
change_table :people do |t|
  t.references :foo_bar_store, references: :store #-> foo_bar_store_id
end

# Model
# app/models/person.rb
class Person < ActiveRecord::Base
  has_one :foo_bar_store, class_name: "Store"
end
5
Richard Peck

Pour développer la réponse de schpet, cela fonctionne dans un create_table Rails 5 directive de migration ainsi:

create_table :chapter do |t|
  t.references :novel, foreign_key: {to_table: :books}
  t.timestamps
end
5
toobulkeh

Sous les couvertures, add_reference se limite à déléguer à add_column et add_index, il vous suffit donc de vous en occuper vous-même:

add_column :people, :foo_bar_store_id, :integer
add_index :people, :foo_bar_store_id
1
boulder