Rails has_many: à travers la recherche par des atsortingbuts supplémentaires dans le modèle de jointure

Nouveau à la fois pour Ruby et Rails mais je suis éduqué à ce jour (ce qui ne signifie apparemment rien, haha).

J’ai deux modèles, Event et User reliés par une table 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 

Ce projet est un calendrier, dans lequel je dois suivre les personnes qui s’inscrivent et qui se grattent pour un événement donné. Je pense que le nombre à beaucoup est une bonne approche, mais je ne peux pas faire quelque chose comme ça:

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

Parce que les événements n’ont pas réellement ces données supplémentaires, le modèle EventUser le fait. Et pendant que je pouvais faire:

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

Cela semble être contraire à “la voie des rails”. Est-ce que n’importe qui peut m’éclairer, cela m’énerve depuis longtemps ce soir (ce matin)?

Que diriez-vous d’append quelque chose comme ceci dans votre modèle d’utilisateur?

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

Après cela, vous devriez pouvoir obtenir des événements actifs pour un utilisateur en appelant simplement:

 User.first.active_events 

Milan Novota a une bonne solution – mais :conditions sont maintenant obsolètes et le bit :conditions => ['event_users.active = ?',true] ne semble tout simplement pas très rail. Je préfère quelque chose comme ça:

 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 

Après cela, vous devriez toujours pouvoir obtenir des événements actifs pour un utilisateur en appelant simplement:

 User.first.active_events 

Même si votre u.events n’appelle pas explicitement la table user_events, cette table est toujours incluse dans le SQL implicitement à cause des jointures nécessaires. Donc, vous pouvez toujours utiliser cette table dans vos conditions de recherche:

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

Bien sûr, si vous envisagez de faire cette recherche beaucoup, alors assurez-vous de lui donner une association distincte, comme le suggère Milan Novota, mais il n’y a pas d’ obligation de le faire de cette façon.

Eh bien, plus de responsabilités sont placées dans User modèle d’ User que ce qui est réellement nécessaire, et il n’y a aucune raison de le faire.

Nous pouvons d’abord définir la scope dans le modèle EventUser , car là où elle appartient, comme:

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

Désormais, un utilisateur peut avoir les deux types d’événements: les événements actifs ainsi que les événements inactifs, ce qui permet de définir la relation dans User modèle User comme suit:

 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 beauté de cette technique réside dans le fait que la fonctionnalité EventUser à être un événement actif ou inactif appartient au modèle EventUser et que, si à l’avenir, la fonctionnalité doit être modifiée, elle ne sera modifiée qu’à un seul endroit: modèle EventUser reflété dans tous les autres modèles.