tutorial rails que ejemplos curso caracteristicas aprender ruby-on-rails ruby-on-rails-3

ruby-on-rails - ejemplos - ruby on rails que es



Alcance con join on: has_many: a través de asociación (6)

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. Dada la instancia de algunos Users current_user , quiero hacer

current_user.meetings.visible

que recuperará una colección de Meetings para las cuales el usuario es un participante donde la columna hidden es false . Lo más cercano que he conseguido es agregar el siguiente alcance a la clase Meetings

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

El scope filtra las Meetings comparación con la tabla MeetingParticipations , sin embargo, no hay join / condition en la tabla MeetingParticipations relacionada con current_user .

El problema con esto es que si current_user y another_user son ambos participantes para alguna instancia de Meetings , se devolverá un registro de Meetings en el conjunto de resultados para cada participante que tenga el conjunto hidden como false . Si current_user tiene true conjunto para hidden para todas las Meetings , si another_user es un participante en cualquiera de esas mismas reuniones con hidden set en false , esas Meetings aparecerán en el conjunto de resultados Meetings.visible .

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


Aquí hay un trazador de líneas:

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

Esto es genial porque puede hacer un alcance fuera de él, una función fuera de él, o simplemente llamarlo a cualquier lugar. También puede agregar más restricciones que desee al hash.


En Rails 4, puede especificar el alcance originalmente definido en el objeto hijo en la asociación misma. 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 le permitiría hacer: user1.visible_meetings y user2.visible_meetings con diferentes conjuntos de resultados


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

@user.meetings.visible


Me parece que no es sensato usar 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 de la asociación dentro del 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.


También podrías hacer:

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


current_user.meetings.merge(MeetingParticipations.visible)