74 votes

Scope with join on :has_many :through association

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 est une colonne booléenne supplémentaire dans la table d'association m2m. Étant donné que certains Users instance current_user Je veux faire

current_user.meetings.visible

qui récupérera une collection de Meetings pour lequel l'utilisateur est un participant où le hidden La colonne est false . Le résultat le plus proche que j'ai obtenu est l'ajout du champ d'application suivant à l'élément Meetings classe

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

En scope filtre les Meetings contre la MeetingParticipations mais il n'y a pas de jointure/condition par rapport à la table MeetingParticipations tableau relatif à current_user .

Le problème est que si current_user y another_user sont tous deux participants pour certains Meetings une instance Meetings dans l'ensemble des résultats sera renvoyée pour chaque participant qui a hidden fixé à false . Si current_user a true fixé pour hidden pour tous Meetings si another_user participe à l'une ou l'autre de ces mêmes réunions avec hidden fixé à false , ces Meetings apparaîtra dans le Meetings.visible l'ensemble des résultats.

Est-il possible d'avoir un champ d'application, comme je l'ai mentionné ci-dessus, qui se joindrait correctement au champ d'application User instance ? Si ce n'est pas le cas, quelqu'un peut-il me recommander une solution ?

2voto

Abass Sesay Points 342

Je sais que la réponse à cette question a été donnée il y a un certain temps, mais je viens de rencontrer un problème similaire et je cherchais la meilleure façon de le résoudre. La solution acceptée est très simple mais je pense qu'elle serait plus propre en déplaçant la portée de l'association de Users à Meeting comme indiqué ci-dessous

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

Grâce à cela, vous pouvez appeler current_user.meetings.hidden

De par sa conception, la réunion détermine désormais ce qui la rend cachée/visible.

-3voto

dkniffin Points 699

Vous pouvez aussi le faire :

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

-4voto

moritz Points 9491

Il me semble qu'il n'est pas judicieux d'utiliser un champ d'application sur la réunion pour votre objectif. Une réunion elle-même n'a pas de visibilité, mais la participation en a une. Je suggérerais donc une extension de l'association au sein de 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

J'espère que cela vous aidera.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X