1

I've been reading this, but can't make sense of writing it into a Rails scope :

find all parent records where all child records have a given value (but not just some child records)

I have a Course, Section, and Quiz, object :

class Course < ActiveRecord::Base
  has_many :course_members
  has_many :members, through: :course_members
  has_many :sections
  has_many :quizzes, through: :sections
end

class Quiz < ActiveRecord::Base
  belongs_to :member
  belongs_to :section
end

class Section < ActiveRecord::Base
  belongs_to :course
  has_many :quizzes
end

I'd like to find all courses of a member, where all quizzes related to that course have the attribute completed = true.

So in my Member class, I'd ideally like to write something like :

has_many :completed_courses, -> { 
   joins(:courses, :quizzes, :sections)
   # .select( 'CASE WHEN quizzes.completed = true then 1 end') ??? maybe ???
}, class_name: 'Course'

Haha! But barring that being too complicated. I've been trying to write this simply in the Course would also be fine.

Trip
  • 26,756
  • 46
  • 158
  • 277

1 Answers1

2
class Member < ActiveRecord::Base
  has_many :courses, through: :course_members
  has_many :course_members

  has_many :completed_courses,
    -> { joins(:quizzes).where.not(quizzes: {completed: [false, nil]}) },
    through: :course_members,
    source: :course
end

If your completed boolean column is NOT NULL, then change [false, nil] above to just simply false

Usage Example

irb(main):002:0> Member.first.completed_courses
  Member Load (0.2ms)  SELECT "members".* FROM "members" ORDER BY "members"."id" ASC LIMIT 1
  Course Load (0.1ms)  SELECT "courses".* FROM "courses" INNER JOIN "sections" ON "sections"."course_id" = "courses"."id" INNER JOIN "quizzes" ON "quizzes"."section_id" = "sections"."id" INNER JOIN "course_members" ON "courses"."id" = "course_members"."course_id" WHERE (NOT (("quizzes"."completed" = 'f' OR "quizzes"."completed" IS NULL))) AND "course_members"."member_id" = ?  [["member_id", 1]]
Jay-Ar Polidario
  • 6,463
  • 14
  • 28
  • That looks like exactly the right answer. Thank you so much. I'm getting the strangest error : `D, [2017-10-24T13:41:08.364579 #5326] DEBUG -- : Member Load (1.6ms) SELECT "members".* FROM "members" ORDER BY "members"."id" ASC LIMIT 1 NoMethodError: undefined method name' for nil:NilClass` .. but nothing has a `name` attribute.. – Trip Oct 24 '17 at 11:41
  • No prob! :) Not sure why the `:members` association is being called. Do you have `default_scope` somewhere? Can you try this instead? `has_many :completed_courses, -> { unscoped.joins(:quizzes).where.not(quizzes: {completed: [false, nil]}) }, class_name: 'Course'` – Jay-Ar Polidario Oct 24 '17 at 11:47
  • I was calling it through the Member class. Where were you thinking to put this call? – Trip Oct 24 '17 at 12:08
  • Yes, I was under the assumption that you're calling that in the `Member` class. So like, `Member.first.completed_courses`. But the `:members` I was talking about is `Course has_many :members`, just in case your `Course` class has a `default_scope`. Did it work? If not, can you provide the full stacktrace? – Jay-Ar Polidario Oct 24 '17 at 12:09
  • Ah it does have a default scope.. ha.. that old bug. – Trip Oct 24 '17 at 12:13
  • Sorry, the `unscoped` didn't work. I was just affirming that I did have a default_scope for `Course` – Trip Oct 24 '17 at 12:16
  • The `unscoped` didn't work? Hmmm, I'll try to replicate this scenario in a few minutes. – Jay-Ar Polidario Oct 24 '17 at 12:17
  • Yah even when I completely remove the `default_scope`, the same error comes up. – Trip Oct 24 '17 at 12:19
  • Ohh I see. Hmmm, then the error seems to be strange then; you're right. Is this error generated directly after running `Member.first.completed_courses`? – Jay-Ar Polidario Oct 24 '17 at 12:20
  • Oh actually I think I have encountered this similar `name` error before. Let me see... – Jay-Ar Polidario Oct 24 '17 at 12:22
  • What Rails version is this? As there seems to be some bug in some older version of Rails matched with a specific version of Ruby; from [here](https://github.com/activescaffold/active_scaffold/issues/380) – Jay-Ar Polidario Oct 24 '17 at 12:24
  • 4.0.13 , ruby 2.1.5 – Trip Oct 24 '17 at 12:26
  • Sorry nevermind the link above, I was looking at a different repo. I'll try to reproduce this now. – Jay-Ar Polidario Oct 24 '17 at 12:28
  • I wonder if this is the same problem you are having? https://stackoverflow.com/questions/38188400/undefined-method-name-for-nil-when-using-custom-has-many-relationship – Jay-Ar Polidario Oct 24 '17 at 12:32
  • I saw that too. I'll try messing around with Ruby. Thanks so much man! – Trip Oct 24 '17 at 12:38
  • No prob! Let me know if you fixed it! :) – Jay-Ar Polidario Oct 24 '17 at 12:39
  • @Trip After reproducing it, I realised that there is a join-table you are using "course_members", and my original answer was wrong all along. Replicating same ruby + rails versions, I managed to now make it work (See updated answer) My apologies. – Jay-Ar Polidario Oct 24 '17 at 12:57
  • Wow I really can't thank you enough. I really appreciate your help brother!! Thank you so much. If it weren't against site rules, I'd DDOS upvote you. :D – Trip Oct 24 '17 at 14:28
  • @Trip haha no worries! I'm glad I could help! :) – Jay-Ar Polidario Oct 24 '17 at 14:58