2011-05-02 11 views
52
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 es una columna booleana extra dentro de la tabla de asociación m2m. Dadas algunas Users ejemplo current_user, quiero hacerAlcance con join on: has_many: a través de la asociación

current_user.meetings.visible 

que recuperará una colección de Meetings para los que el usuario es un participante en la columna de la hidden es false. El más cercano que he conseguido es la adición de la siguiente alcance a la clase Meetings

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

la scope no filtrado del Meetings contra la mesa MeetingParticipations, sin embargo no hay es unirse a/condición contra la mesa MeetingParticipations relacionada con current_user.

El problema con esto es, si current_user y another_user son ambos participantes para algunos Meetings ejemplo, un registro Meetings en el conjunto de resultados serán devueltos por cada participante que se haya hidden conjunto de false. Si tiene current_usertrue conjunto de hidden para todos Meetings, si another_user es un participante en cualquiera de esas mismas reuniones con hidden conjunto de false, los Meetings aparecerá en el conjunto Meetings.visible resultado.

¿Es posible tener un alcance como he mencionado anteriormente que se unirá correctamente en la instancia User? Si no, ¿alguien puede recomendar una solución para esto?

+0

Muy buena pregunta! – deivid

Respuesta

69

Esta es mi solución para su problema:

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 
+0

Gracias por esto, definitivamente la respuesta más simple. – deefour

+1

¿Alguien tiene una sugerencia para lanzar algunas cargas ansiosas en este contexto? ¿Como si una reunión pertenece a un lugar y quiero cargar esos? –

+0

Así que supongo que esto funciona: includes ([: assoc1,: assoc2]). Where .... Geez, pensé que seguramente lo había intentado antes de comentar. –

-3

Me parece que no es sensato utilizar un alcance en Meeting para su propósito. Una reunión en sí misma no tiene visibilidad, pero la participación sí lo tiene. Así que sugeriría una extensión en la asociación dentro de Usuario:

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 

Espero que esto ayude.

50

En los carriles 4, puede especificar el alcance definido originalmente en el objeto secundario de la propia asociación. Corto: no tiene que conocer las partes internas del modelo MeetingParticipation dentro del modelo de Usuario.

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 

Esto permitirá hacer: user1.visible_meetings y user2.visible_meetings con diferentes conjuntos de resultados

+6

Me gusta esta solución, pero para que funcione también necesito agregar: source a: visible_meetings has_many: visible_meetings, class_name: 'Meeting', a través de:: visible_participations, source:: meeting –

+0

Does '-> { visible} '¿necesita cambiarse a un símbolo' -> {: visible} 'o el fragmento de código anterior funciona como está? – chaostheory

+2

@chaostheory siento por la respuesta tardía, pero como es, no es un símbolo en este contexto. –

6
current_user.meetings.merge(MeetingParticipations.visible) 
0

Aquí hay un chiste:

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

Esto es grande porque usted puede hacer una scope de eso, una función fuera de él, o simplemente llámalo a cualquier parte. También puede agregar más restricciones que desee al hash.

-3

También podría hacer:

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