1

I have three related models such as the following, each being the child of the one above:

class Course < ActiveRecord::Base 
  has_many :questions 
end 

class Question < ActiveRecord::Base 
  belongs_to :course
  has_many: :answers

  default_scope order: 'questions.created_at DESC'
  scope :by_answer_count, -> { #orders Questions based on its answer count
    joins(:answers).reorder("count(answers.id) DESC").group(:id)
  }
end 

class Answer < ActiveRecord::Base 
  belongs_to :question
end

What I am having trouble figuring out is: how do I use my scope method by_answer_count, which is in my Question model, to order the list of courses I show by the most number of answers to the least in the index action of CoursesController? Is there a way to utilize that, or should I write a 2 layers down scope method in my CoursesController to get the filter to work?

Thanks!

daspianist
  • 5,336
  • 8
  • 50
  • 94

2 Answers2

4

You should be able to use merge to get that to work.

class Course < ActiveRecord::Base
  scope :by_answer_count, joins(:questions).merge(Question.by_answer_count)
end

Edit

It appears that there is a bug in the way that merge works. https://github.com/rails/rails/issues/3002

You can work around it by adding a relation from course to answers. So your Course class would look like this:

class Course < ActiveRecord::Base
  has_many :answers, through: :questions
  scope :by_answer_count, joins(:questions).merge(Question.by_answer_count)
end

Another option is to use a manual joins clause in your Question class.

joins("answers ON answers.question_id = questions.id").reorder(...)
Sean Hill
  • 14,978
  • 2
  • 50
  • 56
  • This seemed like it should work.. however, I get the error "Association named 'answers' was not found; perhaps you misspelled it?" But strange since this previously worked when put into my `QuestionsController`. Just to make sure, I am calling the function via `Course.by_answer_count` – daspianist Feb 02 '13 at 06:09
  • There is a bug in ActiveRecord::Relation#merge. See my updates for workarounds. – Sean Hill Feb 02 '13 at 06:31
1

I think you should set a counter_cache on your association. Like Ryan Bates suggests in one of his first screencasts: http://railscasts.com/episodes/23-counter-cache-column

I think the following would work:

Course.joins(:questions).order('questions.answer_count DESC')

Or scope:

scope :most_answered, joins(:questions).order('questions.answer_count DESC')

It would also have the benefit of being a single query. I didn't test but it should work.

mathieugagne
  • 2,465
  • 1
  • 17
  • 18
  • Thanks - I looked into counter_cache and its seems like a great feature (and could get things done with far less code). Will do this for my question/answer models. – daspianist Feb 03 '13 at 02:02