Reputation: 2704
I'm building a controller/view that provides a wide selection of player rankings (e.g. "Top 10 Leader Boards".) Using this model:
class Player < ActiveRecord::Base
attr_accessible :name, :games_played, :games_lost, :games_won, games_exited,
:total_kills, :total_deaths, :total_points, :total_coins
end
In my controller I have some obvious query results to pass to my view to populate player ranking lists:
@top_winners = Player.order("games_won DESC").limit(10)
@top_assassins = Player.order("total_kills DESC").limit(10)
I now need to add some sorted rankings that are calculations. Examples:
@most_greedy would be sorted on: :total_coins / :games_played
@most_lethal would be sorted on: :total_kills / :games_played
@most_vanquished would be sorted on: :total_deaths / (:games_lost + :games_exited)
My approach is to get all the players in an array and then use Ruby's array.sort {| a,b | block } → new_array
option. In the case of @most_greedy
I tried this:
rich_players = Player.order("total_coins DESC").limit(30) # only consider top 30 richest
@most_greedy = rich_players.sort {|total_coins, games_played| x / y }.slice(0, 9)
Which generates the error:
undefined local variable or method `x' for #<PlayersController:0x007fb7dac59d08>
Unfortunately my meager AR understanding and Ruby skills are failing me. How can I make this approach work? Is there a different approach to this type of problem? I didn't see anything in the AR Query Guide like this.
Upvotes: 0
Views: 1319
Reputation: 26979
sort is not active record, it is plain old ruby, and uses a block with two parameters to compare both objects, which are going to be Player objects.
@most_greedy = rich_players.sort {|x, y|
(x.total_coins / x.games_played) <=> (y.total_coins / y.games_played)
}.slice(0, 9)
Or even better, using sort_by:
@most_greedy = rich_players.sort_by {|x|
x.total_coins / x.games_played
}.slice(0, 9)
If you want to use the database to calulate (which might give different results, ie, may find a less weathly player that has a better score than by limiting to the 10 top wealthy players) you might try this... (untested)
@most_greedy = Player.select('*, total_coins/games_played as greediness').order('greediness DESC').limit(10)
Upvotes: 2