Rails has_many: by searching for additional attributes in the join model

New to Ruby and Rails, but now I'm studying a book (which obviously means nothing, haha).

I have two models: Event and User are connected through the EventUser table

class User < ActiveRecord::Base has_many :event_users has_many :events, :through => :event_users end class EventUser < ActiveRecord::Base belongs_to :event belongs_to :user #For clarity sake, EventUser also has a boolean column "active", among others end class Event < ActiveRecord::Base has_many :event_users has_many :users, :through => :event_users end 

This project is a calendar in which I have to keep track of people signing and combing my name for this event. I believe that many for many are a good approach, but I cannot do something like this:

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

Since events do not actually have this additional data, the EventUser model does this. And although I could do:

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

This seems to run counter to the "rail track". Can someone enlighten me, it has been calling me for a long time (this morning)?

+69
ruby ruby-on-rails has-many has-many-through
Jan 03 '09 at 10:39
source share
4 answers

How to add something like this to your user model?

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

After that, you can receive active events for the user simply by calling:

 User.first.active_events 
+123
Jan 03 '09 at 11:05
source share

Milan Novota has a good solution, but :conditions now deprecated, and the bit :conditions => ['event_users.active = ?',true] just doesn't seem very rails. I prefer something like this:

 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 

After that, you can still receive active events for the user simply by calling:

 User.first.active_events 
+21
Nov 19 '13 at 17:19
source share

Although your u.events do not explicitly invoke the user_events table, this table is still included in SQL implicitly due to the necessary joins. Thus, you can use this table in your search conditions:

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

Of course, if you plan to do this search a lot, then you are sure to give it a separate association, as Milan Novota suggests, but there is no need for you to do this.

+12
Jan 03 '09 at 12:43
source share

Well, more responsibility is put into the User model than necessary, and there is no good reason for this.

We can first define the area in the EventUser model, because where it really belongs, for example:

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

Now the user can have both types of events: active events, as well as inactive events, so we can define the relationship in the User model as follows:

 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 

The beauty of this method is that the functionality of an active or inactive event belongs to the EventUser model, and if in the future the functionality needs to be changed, it will be changed only in one place: the EventUser model, and the changes will be reflected in all other models.

+4
Nov 10 '16 at 10:06
source share



All Articles