Rails active record querying association with 'exists'

I am working on an app that allows Members to take a survey (Member has a one to many relationship with Response). Response holds the member_id, question_id, and their answer.

The survey is submitted all or nothing, so if there are any records in the Response table for that Member they have completed the survey.

My question is, how do I re-write the query below so that it actually works? In SQL this would be a prime candidate for the EXISTS keyword.

 def surveys_completed
    members.where(responses: !nil ).count
 end 

Solution 1:

You can use includes and then test if the related response(s) exists like this:

def surveys_completed
  members.includes(:responses).where('responses.id IS NOT NULL')
end

Here is an alternative, with joins:

def surveys_completed
  members.joins(:responses)
end

The solution using Rails 4:

def surveys_completed
  members.includes(:responses).where.not(responses: { id: nil })
end

Alternative solution using activerecord_where_assoc: This gem does exactly what is asked here: use EXISTS to to do a condition. It works with Rails 4.1 to the most recent.

members.where_assoc_exists(:responses)

It can also do much more!


Similar questions:

  • How to query a model based on attribute of another model which belongs to the first model?
  • association named not found perhaps misspelled issue in rails association
  • Rails 3, has_one / has_many with lambda condition
  • Rails 4 scope to find parents with no children
  • Join multiple tables with active records

Solution 2:

You can use SQL EXISTS keyword in elegant Rails-ish manner using Where Exists gem:

members.where_exists(:responses).count

Of course you can use raw SQL as well:

members.where("EXISTS" \
  "(SELECT 1 FROM responses WHERE responses.member_id = members.id)").
  count