Ruby on rails-référence le même modèle deux fois?
Est-il possible de mettre en place une double relation activerecord
modèles via le generate scaffold
commande?
Par exemple, si j'avais un User
modèle PrivateMessage
modèle, la table pm devrait garder la trace des deux sender
et recipient
.
évidemment, pour une seule relation, je ferais simplement ceci:
ruby script/generate scaffold pm title:string content:string user:references
Existe-t-il une façon similaire d'établir deux relations?
aussi, est - ce qu'il y a de toute façon à mettre en place des alias pour le les relations?
Donc 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.
4 réponses
Ajouter à votre Modèle
has_one :sender, :class_name => "User"
has_one :recipient, :class_name => "User"
Et vous êtes en mesure d'appeler @message.sender
et @message.recipient
et les deux références au modèle Utilisateur.
au Lieu de user:references
dans votre commande generate vous avez besoin de sender:references
et recipient:references
Voici une réponse complète à cette question, au cas où les gens qui visitent cette question sont nouveaux à Ruby on Rails et ont du mal à tout assembler (comme je l'étais lorsque j'ai examiné cette question pour la première fois).
certaines parties de la solution ont lieu dans vos Migrations et certaines dans 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 spécifiez qu'il y a deux colonnes dans ce tableau qui seront appelées: expéditeur et: destinataire et qui contiennent références à un autre tableau. Les Rails vont en fait créer des colonnes appelées 'sender_id' et 'recipient_id' pour vous. Dans notre cas, ils seront chaque ligne de référence dans la table Users, mais nous spécifions 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é :sender, en spécifiant que cette propriété est liée à la classe User. Les Rails, en voyant "belongs_to: sender", chercheront une colonne dans votre base de données appelée "sender_id", que nous avons définie ci-dessus, et l'utiliser pour stocker la clé étrangère. Alors que vous faites exactement la même chose pour le destinataire.
cela vous permettra d'accéder à votre expéditeur et à votre destinataire, les deux instances du modèle utilisateur, à travers une instance du modèle PrivateMessage, comme ceci:
@private_message.sender.name
@private_message.recipient.email
Voici votre modèle D'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 spécifiant que cette propriété est liée au Modèle PrivateMessage, et que la clé étrangère sur le modèle PrivateMessage qui la relie à cette propriété est appelée "sender_id". Alors vous faites la même chose pour les messages privés reçus.
cela vous permet d'obtenir tous les utilisateurs envoyés ou reçus des messages privés en faisant quelque chose comme ceci:
@user.sent_private_messages
@user.received_private_messages
faire l'une ou l'autre de ces options va retourner un tableau d'instances du modèle PrivateMessage.
....
salut pour avoir les deux côtés de la relation de faire comme ci-dessous dans votre 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 aidera...
Les réponses ci-dessus, tandis que d'excellentes, de ne pas créer de contraintes de clés étrangères dans la base de données, au lieu seulement de créer des index et des colonnes de type bigint. Pour vous assurer 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
ceci assurera que les indices sont créés sur le sender_id
et recipient_id
ainsi que les contraintes de clé étrangère dans la base de données que vous utilisez.