Comment créer « deux côté » plusieurs à plusieurs relations dans Rails?
-
20-09-2019 - |
Question
Supposons que nous ayons un site de photographie. Tout auteur peut souscrire aux mises à jour de tout autre auteur. Il est évident que si l'auteur A est abonné à l'auteur B qui ne veut pas dire que B est abonné à A. Nous construisons des modèles
class Author < ActiveRecord::Base
has_many :subscriptions
has_many :subscribed_by_author, :through => :subscriptions, :source => :subscribed_to
end
class Subscription < ActiveRecord::Base
belongs_to :author
belongs_to :subscribed_to, :class_name => "Author", :foreign_key => "subscribed_to"
end
De cette façon, nous pouvons utiliser
- some_author.subscribed_by_author -. La liste des auteurs à qui some_author est abonnée
- Pour tout abonnement, nous pouvons connaître les deux extrémités (qui est abonné à qui)
Mais la question est de savoir comment obtenir la liste des personnes abonnées à un auteur utilisant des rails seulement (ne pas utiliser SQL ordinaire) i.e. obtenir la réponse à: « Qui est souscrit some_author »
Question: est-il la capacité de Rails pour obtenir la relation de travail des deux côtés dire non seulement l'écriture some_author.subscribed_BY_author
mais ayant some_author_subscribed_TO_author
? S'il y a un, alors qu'est-ce?
P.S. solution évidente consiste à
- Modifier la conception de base de données, l'ajout d'une colonne "direction"
- Créer 2 enregistrements chaque fois qu'un abonnement est créé
-
Ajouter au modèle auteur
has_many: subscribed_BY_author,: par =>: abonnements: source =>: subscribed_to,: conditions => "direction = 'par'"
has_many: subscribed_TO_author,: par =>: abonnements: source =>: subscribed_to,: conditions => "direction = 'à'"
Mais je me demande s'il y a une solution sans changer la conception de base de données.
La solution
# Author model
has_many :subscriptions_to, :class_name => "Subscription", :foreign_key => "subscribed_to"
has_many :subscribed_to_author, :through => :subscriptions_to, :source => :author
Pour autant que je sais - ça marche! :)
Autres conseils
J'utilise HABTM simple pour quelque chose de simple comme ça, mais vous allez avoir besoin d'une table de jointure, peu importe quoi.
create_table :subscriptions do |t|
t.column :author_id, :integer
t.column :subscriber_id, :integer
end
Auteur Point à elle:
class Author < ActiveRecord::Base
has_and_belongs_to_many :subscribers
:class_name => "Author",
:join_table => "subscriptions",
:association_foreign_key => "subscriber_id"
def subscriptions # "subscribers" is already included above
self.subscribers.find(:all, :subscriber_id=>author.id) # hopefully not too
end # much SQL
end
Si vous êtes vraiment engagé à vos noms de méthode:
def subscribed_to_author
subscribers
end
def subscribed_by_author(author)
self.subscribers.find(:all, :subscriber_id=>author.id)
end
Créer des connexions (je fais SubscriptionsController être Resty)
SubscriptionsController < ApplicationController
def create
@author = Author.find(params[:author_id] # author to be subscribed to
@user = current_user # user clicking the "subscribe" button
@author.subscribers << @user # assuming authors should only
@author.save # be able to subscribe themselves
end
end
noms d'affichage, ou quoi que
@author.subscribers.each do |s|
s.name
end
# ...or...and...also...
<%= render :partial => @author.subscribers -%>
<%= render :partial => @author.subscriptions -%>