2017-08-03 115 views
0

我的应用程序是gem acts_as_votable。用户创建的每篇文章都有upvotes和downvotes。Ruby On Rails用户排名

我在测试和Postgresql上使用Sqlite3开发,生产。

posts_controller.rb

class PostsController < ApplicationController 

def upvote 
@post = Post.find(params[:id]) 
@post.liked_by current_user 
redirect_to posts_path 
end 

def downvote 
@post = Post.find(params[:id]) 
@post.downvote_from current_user 
redirect_to posts_path 
end 
end 

users_controller.rb

class UsersController < ApplicationController 

def ranking 
    @users = User.all 
end 

end 

的routes.rb

Rails.application.routes.draw do 

resources :posts do 

member do 

    put "like" => "posts#upvote" 
    put "unlike" => "posts#downvote" 

end 

end 

ranking.html.erb

<% @users.each_with_index do |user,index| %> 

<div class="panel panel-default col-md-offset-4 col-md-4 right"> 

<div class="center"> 

    <h4><b>#<%= index+1 %><b></h4> 

</div> 


<ul class="nav navbar-nav navbar-left margin-left"> 

    <%if user.banned? %> 
    <h5 class="red left">[BANNED]</h5> 
    <%end%> 
    <h4> <%=link_to user.name, user%></h4> 

</ul> 
<ul class="nav navbar-nav navbar-right margin-right"> 

    <h4>Points:<%= user.posts.sum(&:cached_votes_score)%></h4> 

</ul> 

有没有一种简单的方法来创建一个按帖子排序的用户排名?

+0

你用什么数据库? –

+0

sqlite3在生产,开发测试和postgre上 – Michal

回答

0

入住此AR查询:

Post.group(user_id).order('sum_votes DESC').sum(:votes_for) 

可能需要做一些修改

0

PostgreSQL依赖的解决方案基于window functions

# ROW_NUMBER() OVER(ORDER BY votes_sum DESC, id ASC) - 1, 2, 3, 4, 5 
# DENSE_RANK() OVER(ORDER BY votes_sum DESC)   - 1, 1, 2, 2, 3 
# RANK()  OVER(ORDER BY votes_sum DESC)   - 1, 1, 3, 3, 5 

select_clause = <<~SQL 
    users.*, 
    (
    DENSE_RANK() OVER(
     ORDER BY (
     SELECT SUM(cached_votes_score) FROM posts WHERE user_id = users.id 
    ) DESC 
    ) 
) as rank 
SQL 

@users = User.select(select_clause).to_a # .order('rank').to_a if needed 
@users.first.rank # 1 

更新

  • 您必须仔细选择排名功能,具体取决于与具有相同点数的用户相关的规则 。
  • 你必须缓存SUM(cached_votes_score)users表,以避免子选择和加速查询
0

我看了一下AR,做这样的事情。

 @users= User.joins(:posts) 
    .order("sum(cached_votes_score) 
    DESC").group("name").distinct 

它的工作原理。

感谢Pavel和Lun4i