Scope with join on :has_many :through association

In Rails 4, you can specify the scope originally defined in the child object in the association itself. Short: you don't have to know the internals of the MeetingParticipation model within the User model.

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

This would allow you to do: user1.visible_meetings and user2.visible_meetings with different result sets


The clean, associations way to do it is:

has_many :visible_meetings, -> { merge(MeetingParticipations.visible) },
  :source => :meeting, :through => :meeting_participations

To put it in more generic terms: if you have a chained has_many association you can scope the intermediate (through) association via merging the scope. Probably requires Rails 4+.

Otherwise this would have to be done via creating a (probably unwanted) intermediate scoped association as seen in @Paul Pettengill's answer.


current_user.meetings.merge(MeetingParticipations.visible)

This is my solution for your problem:

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