Skip to content

Instantly share code, notes, and snippets.

@ryanchin
Created March 6, 2013 05:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryanchin/5097033 to your computer and use it in GitHub Desktop.
Save ryanchin/5097033 to your computer and use it in GitHub Desktop.
def self.update_rank_by klass
def self.update_rank_by klass
rank_class = (klass.name + "Rank").constantize
rank_by_col = "#{klass.name.underscore}_id".to_sym
rank = total_points = rank_by = 0
sum_points_by(rank_class, rank_by_col).find_in_batches do |points|
User.transaction do
points.each do |point|
rank_by_col_val = point.send(rank_by_col)
# calculate rank
if ( rank_by != rank_by_col_val)
rank = total_points = 0
rank_by = rank_by_col_val
end
#i changed game.total_points to point.points
if point.total_points > total_points
#i changed game.total_points to point.points
total_points = point.total_points
rank +=1
end
# i passed rank - i was getting an error that rank was not known to create_or_update_rank_object
create_or_update_rank_object(rank_class, rank_by_col, point.user_id, rank_by_col_val, point.total_points, rank)
end
end
end
end
# i added rank_class here because it was being passed above - not sure if it should have been removed as a parameter above
def self.sum_points_by(rank_class, rank_by_col)
select_sql = "points.user_id, points.#{rank_by_col},
SUM(points.points) total_points"
Point.select(select_sql).group(:user_id, rank_by_col).
order("#{rank_by_col}, total_points DESC")
end
# i passed in rank because i was geting an error that 'rank' was undefined
def self.create_or_update_rank_object(rank_class, rank_by_col, user_id, rank_by_col_val, total_points, rank)
ro = rank_class.send(
"find_or_initialize_by_user_id_and_#{rank_by_col}",
user_id, rank_by_col_val)
ro.total_points = total_points
ro.rank = rank
ro.save
end
Points table:
points user_id game_type_id game_id
10 1 1 1
10 1 1 1
20 2 1 2
10 2 1 2
25 2 1 3
20 2 1 1
15 1 1 2
GameRanks (actual):
user_id game_id total_points rank
1 1 20 1
2 1 20 1
2 2 30 1
1 2 15 1
2 3 25 1
GameRanks (expected):
user_id game_id total_points rank
1 1 20 1
2 1 20 1
2 2 30 1
1 2 15 2 <= expected to be 2
2 3 25 1
GameTypeRanks (actual - correct as-is):
user_id game_type_id total_points rank
1 1 35 1
2 1 75 2
Trace:
irb(main):001:0> User.update_rank
Scoped order and limit are ignored, it's forced to be batch order and batch size
Point Load (1.1ms) SELECT points.user_id, points.game_id,
SUM(points.points) total_points FROM `points` WHERE (`points`.`id` >= 0) GROUP BY user_id, game_id ORDER BY `points`.`id` ASC LIMIT 1000
(0.6ms) BEGIN
GameRank Load (0.8ms) SELECT `game_ranks`.* FROM `game_ranks` WHERE `game_ranks`.`user_id` = 1 AND `game_ranks`.`game_id` = 1 LIMIT 1
GameRank Load (0.6ms) SELECT `game_ranks`.* FROM `game_ranks` WHERE `game_ranks`.`user_id` = 2 AND `game_ranks`.`game_id` = 2 LIMIT 1
(20.2ms) UPDATE `game_ranks` SET `rank` = 1, `updated_at` = '2013-03-06 05:29:26' WHERE `game_ranks`.`id` = 2
GameRank Load (0.7ms) SELECT `game_ranks`.* FROM `game_ranks` WHERE `game_ranks`.`user_id` = 2 AND `game_ranks`.`game_id` = 3 LIMIT 1
(0.5ms) UPDATE `game_ranks` SET `rank` = 1, `updated_at` = '2013-03-06 05:29:26' WHERE `game_ranks`.`id` = 3
GameRank Load (0.5ms) SELECT `game_ranks`.* FROM `game_ranks` WHERE `game_ranks`.`user_id` = 2 AND `game_ranks`.`game_id` = 1 LIMIT 1
(0.6ms) UPDATE `game_ranks` SET `rank` = 1, `updated_at` = '2013-03-06 05:29:26' WHERE `game_ranks`.`id` = 4
GameRank Load (0.6ms) SELECT `game_ranks`.* FROM `game_ranks` WHERE `game_ranks`.`user_id` = 1 AND `game_ranks`.`game_id` = 2 LIMIT 1
SQL (0.5ms) INSERT INTO `game_ranks` (`created_at`, `rank`, `game_id`, `total_points`, `updated_at`, `user_id`) VALUES ('2013-03-06 05:29:26', 1, 2, 15, '2013-03-06 05:29:26', 1)
(19.5ms) COMMIT
Scoped order and limit are ignored, it's forced to be batch order and batch size
Point Load (0.7ms) SELECT points.user_id, points.game_type_id,
SUM(points.points) total_points FROM `points` WHERE (`points`.`id` >= 0) GROUP BY user_id, game_type_id ORDER BY `points`.`id` ASC LIMIT 1000
(0.5ms) BEGIN
GameTypeRank Load (0.7ms) SELECT `game_type_ranks`.* FROM `game_type_ranks` WHERE `game_type_ranks`.`user_id` = 1 AND `game_type_ranks`.`game_type_id` = 1 LIMIT 1
(1.0ms) UPDATE `game_type_ranks` SET `total_points` = 35, `updated_at` = '2013-03-06 05:29:26' WHERE `game_type_ranks`.`id` = 1
GameTypeRank Load (0.6ms) SELECT `game_type_ranks`.* FROM `game_type_ranks` WHERE `game_type_ranks`.`user_id` = 2 AND `game_type_ranks`.`game_type_id` = 1 LIMIT 1
(19.6ms) COMMIT
=> nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment