2014-03-30 50 views
0

在我的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" %> 

如何渲染根據自己的分數用戶的有序列表?我應該將分數存儲在數據庫中嗎?

+0

什麼是user.score? –

+0

這只是分配給每個用戶的基本評分。這存儲在數據庫中 –

+0

@Katie H首先你不應該寫視圖中的業務邏輯。現在對您的問題,您有業務邏輯來獲取單個用戶的投票計數,在所有用戶的用戶模型中使用相同的邏輯。迭代所有用戶,使用相同的邏輯來獲得投票計數,將它們推入數組並按您選擇的順序排序。 –

回答

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返回NULL而不是0

+0

這真的是一個非常好的方法,但是你錯誤地將票選爲屬性的評論,票是另一張表,看她的代碼se是使用聯想調用user.comments [index] .votes。 –

+1

噢好吧。固定。 –

+0

非常感謝! –

2

Comment屬於User,所以每次有人對此評論投票時,你可以添加此評論的所有者點。直接score

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

再下訂單的用戶:

User.order("score DESC") 
我列添加到用戶需要調用例如: :integer類型的 score然後有人投票時,你會更新這個用戶 score

的情況下,與act_as_voteable寶石

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 

附:

rails g migration add_score_to_users score:integer 

編輯遷移將比分默認設置爲0則:

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

這會更快,並且易於維護,因爲每次投票時,OP肯定會有ajax調用。 –

+1

確實,感謝上帝阿賈克斯打電話並不難;) – rmagnum2002

+0

我該如何運行?用after_save調用?我在哪裏放這個? –

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]是表決計數
用戶[1]包含的字段(例如:用戶[1 ] .id等)

+0

user.rb沒有。我使用acts_as_votable gem,用戶充當選民,評論充當投票 –

+1

這很棒。大聲笑,這仍然是一個很好的解決方案,但不適合你:)對不起 –