【问题标题】:Count the number of records in group_by clause计算 group_by 子句中的记录数
【发布时间】:2014-05-29 14:28:44
【问题描述】:

我将以下类别归为一组:

@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 %>

这没有输出。在混淆这件事之前,我想知道如何解决这个问题。

【问题讨论】:

  • 试试.includes 而不是.joins - 有什么不同吗?
  • .includes 现在再次显示所有类别,但计数仍然没有输出
  • 你为什么要按名字分组?
  • @MikeCampbell 我还能按什么分组?我想列出所有类别名称,以便用户可以单击一个,然后查看属于该类别的所有帖子
  • 为什么会有多个同名的分类?

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


【解决方案1】:

将分组的类别称为@categories 会让人感到困惑,因为这听起来像是类别对象的集合,而实际上它是一个哈希。使用描述性名称(包括在循环中)使您的代码更加清晰。

试试这个:

@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 %>

【讨论】:

  • 是的,你的权利,我应该使用更好的命名约定,谢谢你的提示。你的回答也有效......谢谢
【解决方案2】:

我不确定你为什么使用group_by。但是,您不需要加入,因为您在 posts 上没有任何条件。其他示例建议急切加载帖子,但初始化内存中的所有帖子对象以获取它们的计数似乎有点过头了。不过,您需要进行自己的基准测试。考虑一个 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 } 只会创建一个无意义的散列,其中键作为名称,每个值作为具有一个类别对象的数组,例如:

{
  "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"]}

【讨论】:

  • 感谢您的建议,将研究基准并记录使用 group_by 和不使用它之间的差异。再次感谢您的提示
  • group_by 在您的情况下完全是多余的,无论您是否决定预先加载,所以它会增加开销。
  • 你介意在你的回答中举一个我什么时候使用 group_by 的例子吗?只是想了解为什么我不需要它,您提供的代码有效,但希望了解两者之间的区别,谢谢
  • 感谢您扩展答案,我可以看到您的困惑来自哪里,我现在可以看到为什么没有必要使用 group_by
【解决方案3】:

使用以下代码

@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 %>

希望这会有所帮助! :)

【讨论】:

  • 这将显示每个组中的类别数。他想要每个类别的帖子数
  • @MaxWilliams 我的坏! :( 修改了答案。希望现在有帮助!
【解决方案4】:

您要查找的内容称为counter_cache

在我们的Post 模型中,设置counter_cahe =&gt; 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 来实现这个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多