Est-il possible de mettre en place une double relation dans les modèles activerecord
via le generate scaffold
commande?
Par exemple, si j'avais un modèle User
et un modèle PrivateMessage
, la table private_messages aurait besoin de garder une trace à la fois des sender
et recipient
.
Évidemment, pour une seule relation, je ferais juste ceci:
Ruby script/generate scaffold pm title:string content:string user:references
Existe-t-il une manière similaire d'établir deux relations?
De plus, existe-t-il de toute façon des alias pour les relations?
Donc plutôt que de dire:
@message.user
Vous pouvez utiliser quelque chose comme:
@message.sender
ou @message.recipient
Tout avis serait grandement apprécié.
Merci.
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 les deux font référence au modèle utilisateur.
Au lieu de user:references
dans votre commande de génération dont vous auriez besoin sender:references
et recipient:references
Voici une réponse complète à ce problème, au cas où les personnes visitant cette question sont nouvelles à Ruby on Rails et ont du mal à tout assembler (comme j'étais la première fois que j’ai examiné cela).
Certaines parties de la solution ont lieu dans vos migrations et d'autres dans vos modèles:
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 des références à un autre tableau. Rails créera en fait des colonnes appelées 'sender_id' et 'recipient_id' pour vous. Dans notre cas, elles référenceront chacune des lignes dans la table Users, mais nous spécifions que dans les modèles, pas dans les migrations .
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ée: sender, puis spécifiez que cette propriété est liée à la classe User. Rails, voyant le "appartient à: expéditeur", recherchera une colonne dans votre base de données appelée "sender_id", que nous avons définie ci-dessus, et l'utilisera 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 destinataire, les deux instances du modèle utilisateur, via 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ée: 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'. Ensuite, 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
Si vous effectuez l'une de ces opérations, vous retournerez un tableau d'instances du modèle PrivateMessage.
....
salut pour que les deux relations latérales fassent 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, bien qu'excellentes, ne créent pas de contraintes de clé étrangère dans la base de données, mais créent uniquement des index et des colonnes 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
Cela garantira que les indices seront 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.