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?
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
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 .
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
# 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
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
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