1

我目前在我的应用程序中实现了一个投票系统,并且在我看来,我正在使用以下代码按票数对帖子进行排序:

  <%= render @posts.sort_by { |post| post.votes.count }.reverse %> 

我想按每个帖子的投票数排序,也不希望帖子超过 5 天。如何同时按票数和日期对帖子进行排序。

4

5 回答 5

2

这是错误的。您应该在数据库端进行所有排序操作。对于此示例,请考虑使用 Arel 创建复杂查询或考虑创建计数器缓存列。

于 2012-05-25T20:03:29.767 回答
1

您可以为您的帖子模型添加一个范围,例如:

scope :five_days_ago, lambda { where("created_at >= :date", :date => 5.days.ago) }

然后只需将您的渲染方法调整为以下内容:

<%= render @posts.five_days_ago.sort_by { |post| post.votes.count }.reverse %>

这假设您要保留正在使用的结构。显然,正如其他人所建议的那样,在数据库中完成所有操作是最好的做法。

于 2012-05-25T20:04:19.373 回答
1

卢卡索斯是对的。出于至少两个原因,最好将排序委托给数据库:

  1. 表现
  2. 您可以将更多查询方法链接到它(例如,分页所必需的)。

计数器缓存可能是最好的主意,但对于复杂的查询,让我试一试。在您的 Post 模型中:

class << self
  def votes_descending
    select('posts.*, count(votes.id) as vote_count').joins('LEFT OUTER JOIN votes on votes.post_id = posts.id').group_by('posts.id').order('votes_count desc')
  end

  def since(date)
    where('created_at >= ?', date)
  end

end

所以...

@posts = Post.votes_descending.since(5.days.ago)
于 2012-05-25T20:17:55.213 回答
0

事实上,让数据库进行排序会更好。我会做类似的事情

class Post < ActiveRecord::Base
  default_scope :order => 'created_at DESC'
end

那么您将始终对您的帖子进行排序,如果我没记错的话,最后一个应该是您得到的第一个,这样就可以代替您的“反向”呼叫。然后,您可以使用上面发布的范围仅获取 5 天前的帖子。还要检查数据库中 created_at 列上是否有索引。你可以这样做

SHOW INDEX FROM posts

db 会比 ruby​​ 快得多。

于 2012-05-25T20:18:02.840 回答
0

我想出了另一种方法,虽然我很感激你的帮助,它可能不是最干净的方法,但我做到了

   def most
     range = "created_at #{(7.days.ago.utc...Time.now.utc).to_s(:db)}"
     @posts = Post.all(:conditions => range)
     @title = "All Posts"
     @vote = Vote.new(params[:vote])

     respond_to do |format|
       format.html
       format.json { render :json => @users }
     end
   end 

对于我的控制器

创建了 /most :to => 'posts#most' 的路线

并使用我认为的原始代码进行查看。

我知道这不是最好的方法,但我对编码还是很陌生,所以这是我能弄清楚的最好方法。

于 2012-05-26T07:15:52.463 回答