Sorting by a virtual attribute in Rails 3

前端 未结 2 1723
醉话见心
醉话见心 2021-02-06 18:04

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:

相关标签:
2条回答
  • 2021-02-06 18:58
    1. You shouldn't use 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. This will make it so you only do one db query to load from the posts table.

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

    0 讨论(0)
  • 2021-02-06 19:00

    If you are using MySQL you can do the entire thing using a query:

    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
    

    P.S: You can then modify your Post class to use the SQL version of score if it is present. 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
    

    P.S: The SQLLite3 equivalent is:

    strftime('%s','now') - strftime('%s',posts.created_at)
    
    0 讨论(0)
提交回复
热议问题