Rails has_many: a través de Buscar por atributos adicionales en Join Model

Nuevo en Ruby and Rails, pero ahora tengo un libro educado (que aparentemente no significa nada, jaja).

Tengo dos modelos, Event y User unidos a través de una tabla EventUser

class User  :event_users end class EventUser < ActiveRecord::Base belongs_to :event belongs_to :user #For clarity's sake, EventUser also has a boolean column "active", among others end class Event  :event_users end 

Este proyecto es un calendario, en el que tengo que hacer un seguimiento de las personas que se registran y rascan su nombre para un evento determinado. Me imagino que muchos a muchos es un buen enfoque, pero no puedo hacer algo como esto:

 u = User.find :first active_events = u.events.find_by_active(true) 

Debido a que los eventos en realidad NO TIENEN esa información adicional, el modelo EventUser sí lo hace. Y mientras yo podría hacer:

 u = User.find :first active_events = [] u.event_users.find_by_active(true).do |eu| active_events << eu.event end 

Esto parece ser contrario a “el camino de los Rails”. ¿Alguien puede iluminarme, esto me ha estado molestando por mucho tiempo esta noche (esta mañana)?

¿Qué le parece agregar algo como esto en su modelo de Usuario?

 has_many :active_events, :through => :event_users, :class_name => "Event", :source => :event, :conditions => ['event_users.active = ?',true] 

Después de eso, debería poder obtener eventos activos para un usuario con solo llamar:

 User.first.active_events 

Milan Novota tiene una buena solución, pero :conditions ahora están en desuso y el bit de :conditions => ['event_users.active = ?',true] no parece muy bueno. Prefiero algo como esto:

 has_many :event_users has_many :active_event_users, -> { where active: true }, class_name: 'EventUser' has_many :active_events, :through => :active_event_users, class_name: 'Event', :source => :event 

Después de eso, aún debería poder obtener eventos activos para un usuario con solo llamar:

 User.first.active_events 

Aunque u.events no está llamando explícitamente a la tabla user_events, esa tabla todavía se incluye en el SQL implícitamente debido a las combinaciones necesarias. Por lo tanto, aún puede usar esa tabla en sus condiciones de búsqueda:

 u.events.find(:all, :conditions => ["user_events.active = ?", true]) 

Por supuesto, si planeas hacer esta búsqueda mucho, seguro, dale una asociación por separado, como sugiere Milan Novota, pero no es necesario que lo hagas de esa manera.

Bueno, se está poniendo más responsabilidad en el modelo de User de lo realmente necesario, y no hay una buena razón para hacerlo.

Primero podemos definir el scope en el modelo de EventUser de EventUser porque en realidad pertenece, como:

 class EventUser < ActiveRecord::Base belongs_to :event belongs_to :user scope :active, -> { where(active: true) } scope :inactive, -> { where(active: false) } end 

Ahora, un usuario podría tener ambos tipos de eventos: eventos activos, así como eventos inactivos, por lo que podemos definir la relación en el modelo de User siguiente manera:

 class User < ActiveRecord::Base has_many :active_event_users, -> { active }, class_name: "EventUser" has_many :inactive_event_users, -> { inactive }, class_name: "EventUser" has_many :inactive_events, through: :inactive_event_user, class_name: "Event", source: :event has_many :active_events, through: :active_event_users, class_name: "Event", source: :event end 

La belleza de esta técnica es que la funcionalidad de ser un evento activo o inactivo pertenece al modelo EventUser , y si en el futuro la funcionalidad necesita ser modificada, se modificará solo en un lugar: el modelo de EventUser , y los cambios serán reflejado en todos los otros modelos.