join的范围:has_many:通过关联

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是在m2m关联表内的一个额外的布尔列。 给定一些Users实例current_user ,我想要做的

 current_user.meetings.visible 

它将检索Meetings一个集合,其中用户是hidden列为false的参与者。 我最近得到的是将以下范围添加到Meetings

 scope :visible, joins(:meeting_participations) & MeetingParticipation.visible 

scope Meetings根据MeetingParticipations表进行Meetings筛选,但是没有针对与current_user相关的MeetingParticipations表的MeetingParticipations /条件。

问题在于,如果current_useranother_user都是某个Meetings实例的参与者,则会为每个hidden设置为false参与者返回结果集中的Meetingslogging。 如果current_user对于所有Meetings都设置为hidden ,则如果another_userhidden设置为false那些Meetings的参与者,则这些Meetings将显示在Meetings.visible结果集中。

是否有可能有一个范围,因为我已经提到上面将正确joinUser实例? 如果没有,有人可以推荐一个解决scheme呢?

这是我的解决scheme,您的问题:

 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 

在Rails 4中,你可以在关联本身中指定最初在子对象中定义的范围。 简而言之:您无需了解用户模型中的MeetingParticipation模型的内部结构。

 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 

这将允许你做: user1.visible_meetingsuser2.visible_meetings与不同的结果集

 current_user.meetings.merge(MeetingParticipations.visible) 

这里是一个单行的:

 Meeting.joins(:meeting_participations).where(meeting_participation: { hidden: false, user_id: current_user.id }) 

这很好,因为你可以把它作为一个function,或者只是把它叫做任何地方。 你也可以添加任何你想要的哈希的限制。

你也可以这样做:

 current_user.meeting_participations.visible.map(&:meeting) 

在我看来,为了您的目的而使用会议的范围是不明智的。 会议本身没有可见性,但参与已经。 所以我会build议在用户关联的扩展:

 class User < ActiveRecord::Base has_many :meetings, :through => :meeting_participations do def visible ids = MeetingParticipation. select(:meeting_id). where(:user_id => proxy_owner.id, :visible => true). map{|p| p.meeting_id} proxy_target.where("id IN (?)", ids) end end ... end 

我希望这有帮助。