根据分数对用户进行排序

时间:2014-03-30 23:02:25

标签: ruby-on-rails ruby ruby-on-rails-4

在我的rails应用程序中,对于每个用户,这就是我计算他们得分的方式:

<% comment_vote_count = @user.comments.map{|c| c.votes.count}.sum

   comment_vote_count ||=0 

   comment_vote_count *= 2

   final_score = comment_vote_count + @user.base_score %>

这只是在某些视图中呈现,并未在任何地方保存在数据库中。

我正在尝试按照最高分数到最低分数的顺序填充所有用户的列表,并对结果进行分页。

这就是我在控制器中所拥有的:

  def user_list
    @users = User.order("created_at DESC").paginate(:page => params[:page], :per_page => 10)
    respond_to do |format|
      format.html
    end
  end

在我的user_list视图中

<ol>
<%= render (@users) %>
</ol>

<%= will_paginate @users, :next_label => “next” , :previous_label => '', :class => "next_pagination" %>

如何根据分数呈现有序的用户列表?我应该将分数存储在数据库中吗?

3 个答案:

答案 0 :(得分:2)

如果您使用PostGreSQL作为数据库后端并且不怕弄脏,那么您可以替换

@users = User.order("created_at DESC").paginate(:page => params[:page], :per_page => 10)

@users = User.select('u.*, 2 * case when count(v.id) is null then 0 else count(v.id) end + u.score as cnt')
             .from('users u').joins('left join comments c on c.user_id = u.id')
             .joins('left join votes v on v.comment_id = c.id')
             .group('u.id').order('cnt desc').paginate(:page => params[:page], :per_page => 10)

我在Rails控制台和psql中的本地数据库上对此进行了测试,结果相同 - 用户按总分降序排序。生成的查询是

SELECT u.id, 2 * case when count(v.id) is null then 0 else count(c.votes) end + u.score as cnt
FROM users u
LEFT JOIN comments c on c.user_id = u.id
LEFT JOIN votes v on v.comment_id = c.id
GROUP BY u.id
ORDER BY cnt desc

执行您要查找的计算。 case语句是必要的,因为在对所有NULL求和时,PG返回0而不是NULL

答案 1 :(得分:2)

Comment属于User,因此每次有人投票时,您都可以添加此评论所有者积分。我向用户添加了一列名为score的ex :integer,然后当有人投票时,您将更新此用户score字段:

user = @comment.user
score = @comment.votes.count
user.score = score
user.save

然后通过score列直接订阅用户:

User.order("score DESC")

如果是act_as_voteable gem

<强> Vote.rb

after_create :add_score_to_user

def add_score_to_user
  user = self.voteable.user # gets comment user as voteable is a comment
  score = self.voteable.votes.count # votes count of a comment
  user.score = score
  user.save
  # or user.update_attributes(score: score) instead of last 2 lines
end

如果您想在每次投票后只为用户评分添加一个点,则可以使用increment

def add_score_to_user
  user = self.voteable.user # gets comment user as voteable is a comment
  user.increment!(:score) # this will add +1 to user score for each vote
end

P.S。

rails g migration add_score_to_users score:integer

编辑迁移,将分数默认设置为0,然后:

User.order("score DESC").order('id DESC')

答案 2 :(得分:2)

假设user.rb包含:

has_many :votes, through: :comments

您需要一个初始化器

require 'will_paginate/array'

但是控制器就像这样简单:

@users=User.all.map {|i| [i.votes.count,i]}.sort.reverse.paginate(:page => params[:page], :per_page => 10)

在你看来:

@users.each do |user|...

用户[0]是投票数量
user [1]包含您的字段(例如:user [1] .id等)