1

I am mostly used to writing plain sql for things but I would like to understand arel better. Basically what can I do to count the contents of an :include.

Category.includes(:discussions)

That is my include then discussions has_many comments. I need to know how to count the comments of the category model.

Sorry if this is blatantly obvious and thanks for any help in advance!

Edit: Updated for count on category not discussion.

Hard-Boiled Wonderland
  • 1,359
  • 3
  • 17
  • 32
  • 1
    Could you elaborate on your models please? Is it Category has_many Discussion has_many Comment? And are you trying to get the total number of comments for a Category? – Jits May 29 '11 at 13:52

2 Answers2

1

I'm far from an Arel expert, but my instinct as that you have to get at least a little bit manual in your calculations. Here is how you can get the count for each category making maximal use of arel:

Category.joins(:discussions => :comments).group('categories.id').select('categories.id, COUNT(*) as cnt')

Note that you won't have the full model for categories loaded, but I think this is the fastest way to get the full list of counts. I'm not sure what other approaches you could take with arel, but I think this is the fastest query. Depending your specific application you might want to do things a bit differently.

gtd
  • 16,956
  • 6
  • 49
  • 65
0

Generally, you can use the #count method on any has_many association to get the count. For example:

Category.find(1, :include => :discussions).discussions.first.comments.count

Edit:

A "brute force" approach to counting all the comments on a particular Category:

category = Category.find(1, :include => { :discussions => :comments })    # Check that this eager loading doesn't cause unnecessary overhead.
count = 0
category.discussions.map{|d| count += d.comments.count}

Note that this will create N+1 queries and therefore might not be a performant option. An alternative is to set a counter cache column on the Discussion model and then do this instead:

category = Category.find(1, :include => :discussions)
count = 0
category.discussions.map{|d| count += d.comments_count}

Edit (2):

You can further simplify the summation bit by using the Array#inject method. See example here: How to sum array of numbers in Ruby?

Community
  • 1
  • 1
Jits
  • 9,647
  • 1
  • 34
  • 27
  • Sorry that would have been correct from what I originally explained, what I want to do is to count the comments of the category on a whole and not just the first discussion. – Hard-Boiled Wonderland May 29 '11 at 14:04
  • That was not clear from the question. You asked: "I need to know how to count the comments of the discussion model." Hence my comment for clarification on the question itself. – Jits May 29 '11 at 14:07
  • Thanks for all of the suggestions, I think to save on requests I may use a post count in the tables itself with some testing. category.comments.count did not work at first, not sure why but it is working now. I will try to implement your solutions too and compare performance. Thanks! – Hard-Boiled Wonderland May 29 '11 at 14:22