Scope with join on :has_many :through association

前端 未结 8 1623
孤城傲影
孤城傲影 2020-11-30 19:14
class Users < ActiveRecord::Base
  has_many :meetings, :through => :meeting_participations
  has_many :meeting_participations
end

class Meetings < ActiveRe         


        
相关标签:
8条回答
  • 2020-11-30 19:31

    Here's a one liner:

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

    This is great because you can make a scope out of it, a function out of it, or simply call it anywhere. You can also add any more restrictions you want to the hash.

    0 讨论(0)
  • 2020-11-30 19:33

    I know this question was answered a while back but I just encountered a similar issue and was looking around for the best way to handle this. The accepted solution is very simple but I think it would be cleaner by moving the scope of the association from Users to Meeting as should below

    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
    

    With this, you are able to call current_user.meetings.hidden

    By design, the meeting now dictates what makes it hidden/visible.

    0 讨论(0)
  • 2020-11-30 19:36

    It would seem to me that it is not sensible to use a scope on Meeting for your purpose. A meeting itself has no visibility, but the participation has. So I would suggest an extension on the association within 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
    

    I hope, this helps.

    0 讨论(0)
  • 2020-11-30 19:37

    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

    0 讨论(0)
  • 2020-11-30 19:44

    You could also do:

    current_user.meeting_participations.visible.map(&:meeting)
    
    0 讨论(0)
  • 2020-11-30 19:48

    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

    0 讨论(0)
提交回复
热议问题