Ruby on Rails - référence deux fois le même modèle?
-
20-09-2019 - |
Question
Est-il possible de mettre en place une double relation dans les modèles activerecord
via la commande generate scaffold
?
Par exemple, si j'avais un modèle User
et un modèle PrivateMessage
, la table h aurait besoin de garder une trace des deux l'sender
et recipient
.
Il est évident que, pour une seule relation que je voudrais juste faire ceci:
ruby script/generate scaffold pm title:string content:string user:references
Y at-il une manière similaire à mettre en place deux relations?
En outre, il est de toute façon de mettre en place des alias pour les relations?
Ainsi, plutôt que de dire:
@message.user
Vous pouvez utiliser quelque chose comme:
@message.sender
ou @message.recipient
Tout conseil serait grandement apprécié.
Merci.
La solution
Ajoutez ceci à votre modèle
has_one :sender, :class_name => "User"
has_one :recipient, :class_name => "User"
Et vous pouvez appeler @message.sender
et @message.recipient
et à la fois référence au modèle de l'utilisateur.
Au lieu de user:references
dans votre commande, vous aurez besoin de générer sender:references
et recipient:references
Autres conseils
Voici une réponse complète à cette question, dans le cas de personnes qui visitent cette question sont nouveaux à Ruby on Rails et d'avoir du mal à tout mettre ensemble (comme je l'étais quand je regardais dans ce sujet).
Certaines parties de la solution ont lieu dans votre et quelques-uns dans les migrations de vos modèles:
Migrations
class CreatePrivateMessages < ActiveRecord::Migration
def change
create_table :private_messages do |t|
t.references :sender
t.references :recipient
end
# Rails 5+ only: add foreign keys
add_foreign_key :private_messages, :users, column: :sender_id, primary_key: :id
add_foreign_key :private_messages, :users, column: :recipient_id, primary_key: :id
end
end
Ici, vous indiquez qu'il ya deux colonnes dans ce tableau qui sera nommé: expéditeur et: destinataire et qui contiennent des références à une autre table. Rails en fait créer des colonnes appelées « sender_id » et « recipient_id » pour vous. Dans notre cas, ils seront chacun des lignes de référence dans la table des utilisateurs, mais nous précisons que dans les modèles, pas dans les migrations.
Modèles
class PrivateMessage < ActiveRecord::Base
belongs_to :sender, :class_name => 'User'
belongs_to :recipient, :class_name => 'User'
end
Ici, vous créez une propriété sur le modèle PrivateMessage nommé: l'expéditeur, puis en spécifiant que cette propriété est liée à la classe utilisateur. Rails, voir le « belongs_to: l'expéditeur », va chercher une colonne dans votre base de données appelée « sender_id », que nous avons défini ci-dessus, et l'utiliser pour stocker la clé étrangère. Ensuite, vous faites exactement la même chose pour le destinataire.
Cela vous permettra d'accéder à votre expéditeur et le destinataire, les deux instances du modèle de l'utilisateur, par une instance du modèle PrivateMessage, comme ceci:
@private_message.sender.name
@private_message.recipient.email
Voici votre modèle utilisateur:
class User < ActiveRecord::Base
has_many :sent_private_messages, :class_name => 'PrivateMessage', :foreign_key => 'sender_id'
has_many :received_private_messages, :class_name => 'PrivateMessage', :foreign_key => 'recipient_id'
end
Ici, vous créez une propriété sur le modèle utilisateur nommé: sent_private_messages, en précisant que cette propriété est liée au modèle PrivateMessage, et que la clé étrangère sur le modèle PrivateMessage auquel il se rapporte à cette propriété est appelée « sender_id ». Ensuite, vous faites la même chose pour les messages privés reçus.
Cela vous permet d'obtenir tous les utilisateurs d'un envoyé ou reçu des messages privés en faisant quelque chose comme ceci:
@user.sent_private_messages
@user.received_private_messages
Faire ou l'autre de ceux-ci reviendront un tableau d'instances du modèle PrivateMessage.
....
Salut à tous d'avoir les deux à côte faites comme ci-dessous dans vos deux modèles:
class Message < ActiveRecord::Base
belongs_to :sender,
:class_name => "User",
:foreign_key => "sender_id"
belongs_to :recipient,
:class_name => "User",
:foreign_key => "recipient_id"
end
class User < ActiveRecord::Base
has_many :sent,
:class_name => "Message",
:foreign_key => "sent_id"
has_many :received,
:class_name => "Message",
:foreign_key => "received_id"
end
J'espère que cela vous aide ...
Les réponses ci-dessus, tout en excellent, ne créent pas de contraintes de clé étrangère dans la base de données, au lieu que de créer des index et des colonnes bigint. Pour faire en sorte que la contrainte de clé étrangère est appliquée, ajoutez ce qui suit à votre migration:
class CreatePrivateMessages < ActiveRecord::Migration[5.1]
def change
create_table :private_messages do |t|
t.references :sender
t.references :recipient
end
add_foreign_key :private_messages, :users, column: :sender_id, primary_key: :id
add_foreign_key :private_messages, :users, column: :recipient_id, primary_key: :id
end
end
Cela permettra d'assurer que les indices sont créées sur le sender_id
et recipient_id
ainsi que les contraintes de clé étrangère dans la base de données que vous utilisez.