我有用户模型和出价模型。我希望用户基于作为方法存储的分数来知道他们的等级是什么,即基于user.score
方法的“3/7”。目前,我正在尝试将此geek_rank
方法隐藏到Bid
模型中:
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
由于某种原因,sort_by方法在控制器中工作,但在我尝试在模型中进行排序时却没有。谁能告诉我问题是什么以及我的代码如何糟糕? :)
要澄清:
我得到的实际错误是缺少错误的方法。
答案 0 :(得分:4)
方法find_by_ticket_id
不返回数组;它返回一个出价。
请改用find_all_by_ticket_id
。
bids = Bid.find_all_by_ticket_id(self.ticket.id)
bids = bids.sort_by { |b| b.user.score}
我会按如下方式重写你的方法:
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
在这种方法中,大部分计算都是由DB完成的。
警告1
此方法将为具有相同分数的人返回相同的等级。
E.g:
#name #score #rank
foo 5 4
bar 6 2
kate 6 2
kevin 8 1
警告2
此解决方案的性能优于您的解决方案。但它仍然需要n * 3往返服务器来计算排名。可以进一步优化解决方案,以计算一个SQL中所有用户的排名。
关于排名计算优化的文章:
答案 1 :(得分:0)
那么,从方法返回的分数是有理数,例如3/7还是Fixnums?
如果它们是有理数,那么它们应该能够通过可用的sort_by方法进行比较:
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
但如果它们被评估为fixnums,则3/7返回零,而ruby不能将0与0(整数除法)进行比较
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