计算group_by子句中的记录数

时间:2014-05-29 14:28:44

标签: ruby-on-rails ruby count group-by

我将以下类别组合在一起

@categories = Category.all.group_by { |c| c.name }

在我看来,我正在显示类别名称

<% @categories.each do |c, v| %>
  <li><%= link_to c, blog_path(:name => c) %></li>
<% end %>

例如

Ruby
Ruby On Rails
CSS

我希望实现的是每个类别名称旁边都有该类别名称的帖子总数,所以

Ruby(2)
Ruby On Rails(10)

所以我试过了

@categories = Category.joins(:posts).all.group_by { |c| c.name }

这导致仅显示带有帖子对象的类别(以前所有类别都会显示,无论他们是否有帖子对象),在我的视图中我试过

<% @categories.each do |c, v| %>
  <li><%= link_to c, blog_path(:name => c) %><%= c.count %></li>
<% end %>

哪个没有输出。我以为在问题混淆之前我会问如何解决这个问题,如果有人能够解释答案以及我会非常感激

非常感谢

4 个答案:

答案 0 :(得分:5)

调用分组类别@categories令人困惑,因为这使得它听起来像是Category对象的集合,当它实际上是一个哈希时。使用描述性名称(包括在循环中)可以使代码更清晰。

试试这个:

@category_groups = Category.includes(:posts).all.group_by { |c| c.name }

和视图

<% @category_groups.each do |name, categories| %>
  <li><%= link_to name, blog_path(:name => name) %> (<%= categories.map{|category| category.posts.size}.sum %> posts)</li>
<% end %>

答案 1 :(得分:1)

我不确定你为什么要使用group_by。但是,由于您在posts上没有任何条件,因此您不需要加入。其他示例建议热切加载帖子,但是初始化内存中的所有post对象以获得它们的计数似乎有些过分。你需要做自己的基准测试。考虑一个像另一个回答者建议的counter_cache。

@categories = Category.all

并在视图中:

<% @categories.each do |c| %>
  <li><%= link_to c.name, blog_path(:name => c.name) %> (<%= c.posts.count %> posts)</li>
<% end %>

进一步说明

group_by返回一个带有键的哈希值作为块中的唯一返回值,该值是块计算到该键的原始数组的所有项。以Category.all为例(范围在group_by之前转换为数组,以便我们在此处表示它们):

cats = [
         #<Category name: "foo" ... >,
         #<Category name: "bar" ... >,
         #<Category name: "baz" ... >
       ]

这三个类别具有唯一的名称,因此使用.group_by { |c| c.name }除了创建一个以键为名称的无意义哈希,并且每个值都作为一个具有一个Category对象的数组之外什么都不做:

{
  "foo" => [#<Category name: "foo" ... >],
  "bar" => [#<Category name: "bar" ... >],
  "baz" => [#<Category name: "baz" ... >]
}

以下是您可以使用group_by实现某些效果的示例:

languages = ["Ada", "C++", "CLU", "Eiffel", "Lua", "Lisp",
             "Perl", "Python", "Smalltalk"]
languages_grouped_by_first_letter = languages.group_by { |s| s[0] }     
=> {"A"=>["Ada"], "C"=>["C++", "CLU"], "E"=>["Eiffel"], "L"=>["Lua", "Lisp"], "P"=>["Perl", "Python"], "S"=>["Smalltalk"]}

答案 2 :(得分:0)

使用以下代码

@categories = Category.all.group_by { |c| c.name }

编写Hepler以查找post_count

def post_count(category_ids)
  Post.where(:category_id => category_ids)
end

在视图中:

<% @categories.each do |c, v| %>
  <li><%= link_to c, blog_path(:name => c) %>(<%= post_count(v.map(&:id)) %>)</li>
<% end %>

希望这有帮助! :)

答案 3 :(得分:0)

您要找的是counter_cache

在我们的Post模型中,设置counter_cahe => true

class Post < ActiveRecord::Base

belongs_to category,:counter_cache => true

end

posts_count列添加到categories表并执行此操作

@category_groups = Category.find(:all)

<% @category_groups.each do |c| %>
  <li><%= link_to name, blog_path(:name => c) %>(<%= posts_count)</li>
<% end %>

查看 Railscast 以实现此目的。