I have a user model and a bid model. I want the user to know what their rank is based upon a score stored as a method, i.e. "3/7" based upon user.score
method. Currently, I'm trying to tuck this geek_rank
method into the Bid
model as:
def user_rank(my_id)
#Finds all bids associated with parent ticket object
bids = Bid.find_by_ticket_id(self.ticket.id)
bids = bids.sort_by { |b| b.user.score}
i = 0
for b in bids
i += 1
if b.user_id.to_i == my_id.to_i
myrank = i
end
开发者_运维技巧end
user_rank = myrank.to_s + "/" + i.to_s
end
For some reason the sort_by method works in the controller but not when I try to sort in the model. Can anyone tell me what the problem is along with how my code sucks? :)
TO CLARIFY:
The actual error I'm getting is a method missing error.
The method find_by_ticket_id
DOES not return an array; it returns a Bid.
Use find_all_by_ticket_id
instead.
bids = Bid.find_all_by_ticket_id(self.ticket.id)
bids = bids.sort_by { |b| b.user.score}
I would rewrite your method as follows:
def user_rank(my_id)
# find the bid by the given id
score = Bid.find_by_id(my_id).user.score
# find the total number of bids for the ticket
count = Bid.count(:conditions => {:ticket_id => self.ticket.id})
# find the rank
rank = Bid.count(:conditions => ["ticket_id =? AND users.score > ? ",
self.ticket.id, score], :joins => :user) + 1
"#{rank}/#{count}"
end
In this approach most of the calculation is done by the DB.
Caveat 1
This method will return the same rank for people with the same score.
E.g:
#name #score #rank
foo 5 4
bar 6 2
kate 6 2
kevin 8 1
Caveat 2
This solution performs better than your solution. But it still requires n * 3 round trips to the server to calculate the rank. Solution can be further optimized to calculate the rank of all the users in one SQL.
Articles about rank calculation optimization:
Article 1
so, are the scores being returned from the method as rational numbers, eg 3/7 or are they Fixnums ?
if they are rationals then they should be able to be compared by the enumarable sort_by method:
ruby-1.8.7-p299 > require 'mathn'
=> true
ruby-1.8.7-p299 > Rational
=> Rational
ruby-1.8.7-p299 > Rational(3/7)
=> 3/7
ruby-1.8.7-p299 > Rational(3/7) <=> Rational(5/7)
=> -1
but if they are being evaluated as fixnums then 3/7 returns zero, and ruby cant compare 0 to 0 (integer division)
ruby-1.8.7-p299 > 3/7
=> 0
ruby-1.8.7-p299 > 5/7
=> 0
ruby-1.8.7-p299 > 3/7 <=> 5/7
=> 0
ruby-1.8.7-p299 > 5/7 <=> 5/7
=> 0
ruby-1.8.7-p299 > 8/7 <=> 5/7
=> 1
ruby-1.8.7-p299 > 7/7 <=> 7/7
=> 0
精彩评论