Sphere with joining: has_many: through union

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 is an optional boolean column in the m2m mapping table. Given some Users instance of current_user , I want to do

 current_user.meetings.visible 

which will retrieve the Meetings collection for which the user is a member, where the hidden column is false . The closest I got is adding the following scope to the Meetings class

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

scope filters Meetings according to the MeetingParticipations table, however there is no join / condition regarding the MeetingParticipations table associated with current_user .

The problem is that if current_user and another_user are participants for the Meetings instance, the Meetings record in the result set will be returned for each participant whose hidden set to false . If current_user has true for hidden for hidden for all Meetings , if another_user is a participant in any of the same meetings with hidden set to false , those Meetings will appear in the Meetings.visible result set.

Is it possible to have a scope, as I mentioned above, that will correctly join the User instance? If not, can someone recommend a solution?

+51
ruby-on-rails ruby-on-rails-3
May 2 '11 at 11:56
source share
6 answers

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 
+67
03 Mar. 2018-12-12T00:
source share
โ€” -

In Rails 4, you can specify the area originally defined in the child in the association itself. In short: you don't need to know the insides of the MeetingParticipation model in 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 will allow you to do: user1.visible_meetings and user2.visible_meetings with different result sets

+46
Oct 12 '13 at 1:06 on
source share
 current_user.meetings.merge(MeetingParticipations.visible) 
+6
Apr 08 '16 at 5:11
source share

Here is one liner:

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

This is great because you can make a volume, a function from it, or just call it anywhere. You can also add any restrictions that you want to use for the hash.

0
Apr 12 '16 at 23:25
source share

You can also do:

 current_user.meeting_participations.visible.map(&:meeting) 
-2
Apr 28 '16 at 18:52
source share

It seems to me reasonable to use the scope of the meeting for your purpose. The meeting itself does not have visibility, but it does. Therefore, I would suggest an extension to the association in User:

 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 

Hope this helps.

-3
May 2 '11 at 14:38
source share



All Articles