加入的范围:has_many:通过关联

dee*_*our 67 ruby-on-rails ruby-on-rails-3

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
Run Code Online (Sandbox Code Playgroud)

hidden是m2m关联表中的额外布尔列.举个Users例子current_user,我想做

current_user.meetings.visible
Run Code Online (Sandbox Code Playgroud)

这将检索Meetings用户是hidden列所属参与者的集合false.我得到的最接近的是在Meetings课堂上添加以下范围

scope :visible, joins(:meeting_participations) & MeetingParticipation.visible
Run Code Online (Sandbox Code Playgroud)

scope不过滤MeetingsMeetingParticipations表,但没有对加入/条件MeetingParticipations相关的表current_user.

这个问题是,如果current_user并且another_user都是某个Meetings实例的Meetings参与者,hidden则将为已设置为的每个参与者返回结果集中的记录false.如果current_user已为all true设置,if if 参与任何设置为的相同会议,那么这些会出现在结果集中.hiddenMeetingsanother_userhiddenfalseMeetingsMeetings.visible

是否有可能拥有我上面提到的范围,它将正确加入User实例?如果没有,有人可以推荐一个解决方案吗?

And*_*oss 85

这是我的问题解决方案:

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
Run Code Online (Sandbox Code Playgroud)

@user.meetings.visible

  • 我不知道你可以将一个块应用于关联定义.零想法.我已经和Rails合作了7年......很好. (7认同)
  • 任何人都建议在这种情况下进行一些急切的加载?例如,如果会议属于某个地点,而我想急于加载这些地点? (2认同)

Pau*_*ill 61

在Rails 4中,您可以在关联本身中指定最初在子对象中定义的范围.简短:您不必知道User模型中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
Run Code Online (Sandbox Code Playgroud)

这将允许您执行:user1.visible_meetingsuser2.visible_meetings使用不同的结果集

  • 我喜欢这个解决方案,但为了让它工作,我还需要添加:source到:visible_meetings has_many:visible_meetings,class_name:'Meeting',::: visible_participations,source :: meeting (6认同)
  • @chastheory对于迟到的回复感到抱歉,但是在这种情况下,它不是一个符号. (2认同)
  • 就像@DarrenHicks评论的那样,我不得不添加`:source`,但我可以省略`:class_name` (2认同)

thi*_*ign 9

干净的关联方式是:

has_many :visible_meetings, -> { merge(MeetingParticipations.visible) },
  :source => :meeting, :through => :meeting_participations
Run Code Online (Sandbox Code Playgroud)

用更通用的术语来说:如果您有一个链式has_many关联,您可以through通过合并范围来确定中间 ( ) 关联的范围。可能需要 Rails 4+。

否则,这必须通过创建(可能不需要的)中间范围关联来完成,如@Paul Pettengill 的回答所示。

  • 我认为最好的答案 (3认同)

wot*_*oto 7

current_user.meetings.merge(MeetingParticipations.visible)
Run Code Online (Sandbox Code Playgroud)