2013-05-08 75 views
0

我有一個應用程序,用戶可以收到遊戲積分。我的代碼中存在一個錯誤,這意味着在過去的一週內(在GameTypeRank表中)按Game_Type對每個用戶的點數進行小計和排名。如果用戶在過去一週內有積分,這可以正常工作,但如果用戶在過去一週內沒有積分,則無法正常工作。如果用戶沒有積分,那麼他們應該在GameTypeRank中更新爲0分,否則他們會保留最後的排名直到更新(並且排名不正確)。Rails:與Rails查詢相關的邏輯錯誤

# user.rb: 
def self.update_game_type_weekly_rank 
    @game_types = GameType.all 
    @game_types.each do |game_type| 

    # this query is where the bug is since it is possible a User has no Points 
    @user_with_points = Point.where("game_type_id = ? and created_at >= ?", game_type.id, 1.week.ago).sum(:points, :group => :user_id, :order => 'sum(points) desc') 
    rank = point_counter = 0 

    @user_with_points.each do |user_id, points| 
     @game_type_rank = GameTypeRank.find_or_create_by_user_id_and_game_type_id(user_id, game_type.id) 
     if points != point_counter 
     point_counter = points 
     rank += 1 
     end 
     @game_type_rank.weekly_rank = rank 
     @game_type_rank.weekly_points = points 
     @game_type_rank.save 
    end 
    end 
end 

# Models 

# game_type_rank.rb 
# fields - user_id, game_type_id, weekly_points, weekly_rank 
belongs_to :game_type 
belongs_to :user 

# point.rb 
# fields - user_id, points, game_type_id 
belongs_to :game 
belongs_to :game_type 
belongs_to :user 

我可以創建每週運行,並創建點記錄(含Point.points = 0),對於沒有任何一週的每個用戶,但是這是一個貧窮的解決方案的方法。

我也可能會在方法開始時爲每個GameTypeRank記錄初始化weekly_pointsweekly_rank,但對我來說這似乎效率低下(我不確定是否執行此操作的最佳方式)。

# Sample Data 
Points 
|user_id|points|game_type_id|created_at 
|1  | 10 |   1|2013-05-07 
|1  | 10 |   2|2013-05-07 
|2  | 20 |   2|2012-12-31 
|1  | 5 |   2|2012-12-31 

before weekly_update - Game_Type_Ranks 
|user_id |game_type_id | weekly_points | weekly_rank| 
|1  |2   |5    |2 
|2  |2   |20    |1 

after weekly_update - Game_Type_Ranks 
|user_id |game_type_id | weekly_points | weekly_rank| 
|1  |1   |10    |1 
|1  |2   |10    |1 
|2  |2   |20    |1 

what should happen after weekly_update - Game_Type_Ranks 
|user_id |game_type_id | weekly_points | weekly_rank| 
|1  |1   |10    |1 
|1  |2   |10    |1 
|2  |2   |0    |2 <== update for user_id 2 
+0

一些示例輸入數據以及預期和實際輸出將會很有用。 – 2013-05-08 00:21:02

+0

我添加了一些示例數據,謝謝 – yellowreign 2013-05-08 00:33:59

+0

本週沒有活動的用戶是否需要每週有0個點。我們可以將它們排除在外嗎? – bennick 2013-05-08 16:25:12

回答

0

的主要問題是你沒有訪問誰擁有現有的排名,但並沒有積極爲當前周@user_with_points對於給定的GameType用戶。

爲什麼不保留原樣,而是使用updated_at時間戳。在打電話給GameTypeRank對象時,只需拉取上週更新的對象即可。

# some controller 
GameTypeRank.where("id = ? and updated_at >= ?", id, 1.week.ago) 

但是這個你失去了把舊的能力傾斜用戶weekly_points 0

另一種方法是通過循環具有對給定的遊戲類型分不分時間,像這樣所有用戶:

# user.rb: 
def self.update_game_type_weekly_rank 
    @game_types = GameType.all 
    @game_types.each do |game_type| 

    @user_with_points = Point.where("game_type_id = ?", game_type.id).sum(:points, :group => :user_id, :order => 'sum(points) desc') 
     rank = point_counter = 0 
     @user_with_points.each do |user_id, points| 
     @game_type_rank = GameTypeRank.find_or_create_by_user_id_and_game_type_id(user_id, game_type.id) 
     if points != point_counter 
      point_counter = points 
      rank += 1 
     end 
     @game_type_rank.weekly_rank = rank 
     @game_type_rank.weekly_points = points 
     @game_type_rank.save 
     end 
    end 

    end 
end 

之後,你的表應該是你想要的方式。現在,您可能會意識到這一點是有代價的。也許你可能會因爲不活動而被切斷。比如說6個月。

# users.rb 
.... 
@user_with_points = Point.where("game_type_id = ? and created_at >= ?", game_type.id, 6.months.ago).sum(:points, :group => :user_id, :order => 'sum(points) desc') 
.... 

# some controller 
GameTypeRank.where("id = ? and created_at >= ?", id, 6.months.ago) 

這兩種方法都有一些低效率,但它完成了工作。另外,您可能正在使用cron作業和/或後臺作業運行此方法,因此對用戶的影響應爲零。

+0

謝謝你的回答。在第一個選項中,正如你所指出的那樣,它不會糾正GameTypeRank在前一週有用戶點數的情況,但不是這一點。我認爲第二種選擇的問題在於,即使他們本週沒有積分,它也會對每個用戶進行排名。 GameTypeRank實際上有一個排名,weekly_rank和monthly_rank(和相應的點字段),所以我已經有了選項2的代碼(省略created_at),對於我的總體排名,點字段,但不是每月或每週。 – yellowreign 2013-05-08 20:59:58