Glenn Jones's Blog

Rails 4 has many through source with condition

To retrieve a collection of related models through a has_many :through relation, with a different name (:source) and one or many conditions, use the following:

class Event < ActiveRecord::Base
  has_many :invitees, 
        ->{ where "invites.accepted = false" }, 
        through: :invites, 
        source: :user
  has_many :participants, 
        ->{ where "invites.accepted = true" },
        through: :invites, 
        source: :user 

Now when you do Event.first.invitees or Event.first.participants, you’ll get the right Activerecord CollectionProxy as usual.

This assumes there are the additional models Invite (with an attribute accepted) and User.

The lambda allows you to place the condition, the through allows you to grab the associated records and the source allows you to name which type of model is to be associated. Because I’m renaming the set of users as ‘invitees’ or ‘participants’, that’s necessary.

I found out that the order of the lambda -> through -> source is essential to make this work, so make sure you get that right.

Retrieving records this way keeps my controller code cleaner by not having to do conditions on the retrieved collection. Also, knowing you can filter associated records through conditions ‘in’ the model, has prevented me from making an overcomplicated database design.

comments powered by Disqus