简体   繁体   English

按Rails 3中的虚拟属性排序

[英]Sorting by a virtual attribute in Rails 3

BACKGROUND: I have a set of Posts that can be voted on. 背景:我有一组可以投票的帖子。 I'd like to sort Posts according to their "vote score" which is determined by the following equation: 我想根据他们的“投票得分”对帖子进行排序,这可以通过以下公式确定:

( (@post.votes.count) / ( (Time.now - @post.created_at) ** 1 ) ) ((@ post.votes.count)/((Time.now - @ post.created_at)** 1))

I am currently defining the vote score as such: 我目前正在定义投票得分:

  def vote_score(x)
   ( (x.votes.count) / ( (Time.now - x.created_at) ** 1 ) )
  end

And sorting them as such: 并将它们排序为:

@posts = @posts.sort! { |a,b| vote_score((b) <=> vote_score((a) }

OBJECTIVE: This method takes a tremendous toll on my apps load times. 目标:此方法对我的应用程序加载时间造成巨大损失。 Is there a better, more efficient way to accomplish this kind of sorting? 有没有更好,更有效的方法来完成这种排序?

If you are using MySQL you can do the entire thing using a query: 如果您使用MySQL,您可以使用查询执行整个操作:

SELECT   posts.id,
         (COUNT(votes.id)/(TIME_TO_SEC(NOW()) - TIME_TO_SEC(posts.created_at))) as score
FROM     posts INNER JOIN votes ON votes.post_id = posts.id
GROUP BY posts.id
ORDER BY score DESC

Or: 要么:

class Post
  scope :with_score, select('posts.*')
    .select('(COUNT(votes.id)/(TIME_TO_SEC(NOW()) - TIME_TO_SEC(posts.created_at))) as score')
    .joins(:votes)
    .group('posts.id')
    .order('score DESC')
end

Which would make your entire query: 这将使您的整个查询:

@posts = Post.with_score.all

PS: You can then modify your Post class to use the SQL version of score if it is present. PS:然后,您可以修改Post类以使用分数的SQL版本(如果存在)。 You can also make the score function cached in an instance so you don't have to re-calculate it every time you ask for a post's score: 您还可以在实例中缓存分数功能,这样您每次要求获得帖子分数时都不必重新计算分数:

class Post
  def score
    @score ||= self[:score] || (votes.count/(Time.now.utc - x.created_at.utc)
  end
end

PS: The SQLLite3 equivalent is: PS:SQLLite3的等价物是:

strftime('%s','now') - strftime('%s',posts.created_at)
  1. You shouldn't use sort! 你不应该使用sort! if you are going to assign to the same variable (it is wrong in this case), you should change the sort to: 如果要分配给同一个变量(在这种情况下是错误的),您应该将排序更改为:

     @posts.sort!{|a, b| vote_score(b) <=> vote_score(a) } 
  2. It looks like you are counting the votes for Post each time you call another Post which is hitting the database quite a bit and probably the source of the toll on your load times, you can use a counter_cache to count each time a vote is made and store that in the posts table. 看起来你每次打电话给另一个帖子时都会计算Post的票数,这个帖子很可能是你的加载时间的来源,你可以使用counter_cache来计算每次投票的时间和将它存储在posts表中。 This will make it so you only do one db query to load from the posts table. 这样就可以让你只从post表中加载一个db查询。

http://guides.rubyonrails.org/association_basics.html http://guides.rubyonrails.org/association_basics.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM