Rails 4 has many through source with condition

by Glenn square thumb Glenn Jones, published on 03/06/16

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 
end

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.

Did you find this article useful? Be the first to receive new articles when I publish them by signing up for my newsletter

>> Autonomous management of static websites with prismic.io, circleci and github pages

<< Building a static website with middleman and prismic.io

Back to glennjon.es

comments powered by Disqus