Rails按计数通过两个模型实例排序

时间:2015-01-25 22:48:16

标签: ruby-on-rails ruby

我有一些代码,每个项目都可以投票。在我的观点中,我想按照从最高到最低的投票顺序列出每个项目。

我找到了一种方法,但是有更好的方法吗?

我的方式:

控制器

class Admin::ProjectsController < ApplicationController
  def index
     @projects = Project.all.sort_by { |project| project.votes.count }
  end
end

视图

- @projects.each do |project|
  %li= project.name
  %li= project.teacher_firstname
  %li= project.teacher_lastname
  %li= project.votes.count

我试图按照Project.votes.all.order(:desc)的方式做一些事情,但显然这不起作用,但这就是我想要做的事情。

然后有人把我指向:counter_cache,但这似乎有点太多了。无需添加计数列。

还有其他建议吗?

更新 好的,有两件事

  1. @ jgautsch的工作,但我很好奇,这是一种类方法不是我 想让这个实例方法?或者没关系?只是 脱掉自己?我有时会感到困惑(就像阅读文章一样 当它适用于比喻类方法时。

  2. 此外,我注意到我只获得了已经投票的项目。 即使有0票,我将如何继续显示它们?我甚至拿出了limitnum参数

2 个答案:

答案 0 :(得分:2)

查看此问题:Rails 3 ActiveRecord: Order by count on association

如链接问题所述,您可以使用counter_cache并将查询保留在一个表中(此处添加列没有任何问题),或执行类似此操作(未经测试):

class Project
  has_many :votes

  def self.top_voted(num = 10)
    select("projects.id, OTHER_ATTRS_YOU_NEED, count(votes.id) AS votes_count")
    .joins(:votes)
    .group("projects.id")
    .order("votes_count DESC")
    .limit(num)
  end
end

Project.top_voted(5) # top 5 most voted projects

答案 1 :(得分:1)

有趣的问题。你可以这样做:

Project.select('*, (SELECT count(*) FROM votes WHERE votes.project_id=project.id) as vote_count').order("vote_count DESC")

丑陋,我知道,但至少它只是一个查询。

如果有完全的ORM方法可以做到这一点会很酷,例如:

Project
  .select(vote_count: Vote.where("project_id = project.id").count)
  .order(vote_count: :desc)

<强>更新 另一种功能方式:

Project
  .select(
    Vote
      .select('count(*)')
      .where('project_id=projects.id')
      .to_sql.sub(/(.*)/, '*, (\1)as vote_count'))
  .order("vote_count DESC")

或者我们可以通过直接使用Arel或通过投票搜索(并在项目内部加入)而不是按项目搜索(并在内部加入投票)来实现更多的ORMed。