class Users < ActiveRecord::Base
has_many :meetings, :through => :meeting_participations
has_many :meeting_participations
end
class Meetings < ActiveRecord::Base
has_many :users, :through => :meeting_participations
has_many :meeting_participations
end
class MeetingParticipations < ActiveRecord::Base
belongs_to :user
belongs_to :meeting
scope :hidden, where(:hidden => true)
scope :visible, where(:hidden => false)
end
hidden
est une colonne booléenne supplémentaire dans la table d'association m2m. Étant donné une instance Users
__ _current_user
, je veux faire
current_user.meetings.visible
qui récupère une collection de Meetings
pour laquelle l'utilisateur est un participant où la colonne hidden
est false
. Le plus proche que j'ai obtenu ajoute la portée suivante à la classe Meetings
scope :visible, joins(:meeting_participations) & MeetingParticipation.visible
La scope
filtre la Meetings
contre la table MeetingParticipations
, mais il n'y a pas de jointure/condition contre la table MeetingParticipations
associée à current_user
.
Le problème avec ceci est que, si current_user
et another_user
sont tous deux participants pour une instance Meetings
, un enregistrement Meetings
dans le jeu de résultats sera renvoyé pour chaque participant pour lequel hidden
est défini sur false
. Si current_user
a true
défini pour hidden
pour tout Meetings
, si another_user
est un participant à l'une de ces mêmes réunions avec hidden
défini sur false
, ces Meetings
apparaîtront dans l'ensemble de résultats Meetings.visible
.
Est-il possible d'avoir, comme je l'ai mentionné ci-dessus, une portée qui se joindra correctement à l'instance User
? Si non, quelqu'un peut-il recommander une solution à cela?
Ceci est ma solution pour votre problème:
class User < ActiveRecord::Base
has_many :meeting_participations
has_many :meetings, :through => :meeting_participations do
def visible
where("meeting_participations.visible = ?", true)
end
end
end
@user.meetings.visible
Dans Rails 4, vous pouvez spécifier la portée définie à l'origine dans l'objet enfant dans l'association elle-même. En bref: vous n'avez pas besoin de connaître les éléments internes du modèle MeetingParticipation dans le modèle User.
class User < ActiveRecord::Base
has_many :meeting_participations
has_many :meetings, :through => :meeting_participations
has_many :visible_participations, -> { visible }, :class_name => 'MeetingParticipation'
has_many :visible_meetings, :source => :meeting, :through => :visible_participations
end
class Meeting < ActiveRecord::Base
has_many :meeting_participations
has_many :users, :through => :meeting_participations
end
class MeetingParticipation < ActiveRecord::Base
belongs_to :user
belongs_to :meeting
scope :hidden, -> { where(:hidden => true) }
scope :visible, -> { where(:hidden => false) }
end
Cela vous permettrait de faire: user1.visible_meetings
et user2.visible_meetings
avec différents ensembles de résultats
current_user.meetings.merge(MeetingParticipations.visible)
Je sais que cette question a reçu une réponse il y a quelque temps, mais je viens de rencontrer un problème similaire et je cherchais la meilleure façon de gérer cela. La solution acceptée est très simple, mais je pense qu’elle serait plus propre en déplaçant la portée de l’association de Users
à Meeting
comme il convient ci-dessous
class Users < ActiveRecord::Base
has_many :meetings, :through => :meeting_participations
has_many :meeting_participations
end
class Meetings < ActiveRecord::Base
has_many :users, :through => :meeting_participations
has_many :meeting_participations
scope :hidden, -> { where('meeting_participations.hidden = ?', true) }
scope :visible, -> { where('meeting_participations.hidden = ?', false) }
end
class MeetingParticipations < ActiveRecord::Base
belongs_to :user
belongs_to :meeting
scope :hidden, where(:hidden => true)
scope :visible, where(:hidden => false)
end
Avec cela, vous pouvez appeler current_user.meetings.hidden
De par sa conception, la réunion dicte maintenant ce qui la rend cachée/visible.
La manière propre et associative de le faire est:
has_many :visible_meetings, -> { merge(MeetingParticipations.visible) },
:source => :meeting, :through => :meeting_participations
En termes plus génériques: si vous avez une association chaînée has_many
, vous pouvez définir l’association intermédiaire (through
) en fusionnant la portée. Nécessite probablement Rails 4+.
Autrement, il faudrait créer une association de portée intermédiaire (probablement non désirée), comme le montre la réponse de Paul Pettengill.
Voici un one liner:
Meeting.joins(:meeting_participations).where(meeting_participation: { hidden: false, user_id: current_user.id })
C'est formidable car vous pouvez en faire une portée, une fonction ou simplement l'appeler n'importe où. Vous pouvez également ajouter d'autres restrictions à votre hachage.