Hello. I do analog stackoverflow for training purposes. There is a question page (show). It renders the answers:

.answers_block = render @answers 

I get the answers by this method

 def get_answers @answers = Answer.where(question_id: @question.id).order(created_at: :desc) end 

There is also a vote for each answer. There is a method that considers "response rating"

 def votes_count(answer) @answer = Answer.find(answer.id) @votes = @answer.get_upvotes.size - @answer.get_downvotes.size end 

I use the gem 'acts_as_votable' gem to count the votes. How to implement sorting of answers by rating when rendering?

  • Add to the model a field in which the current amount of votes will be stored. When adding / deleting a voice, change its values. When displaying answers - sort by it. - MAXOPKA

1 answer 1

Uh ... throw out your votes_count . It doesn’t work at the database level, but you don’t want to sort on the Ruby side, because you can only select a sample (for example, one page) on the Ruby side (or using clever techniques like the kth maximum, which with the database will only add problems). Of course, you can do JOIN + COUNT + GROUP BY on voices, but this will be a re-implementation of this method in another language (SQL). Not cool.

The acts_as_votable has columns for caching , including the current total weight of votes:

 add_column :posts, :cached_weighted_total, :integer, :default => 0 

... and for sorting by rating, you can simply sort by the value of this column.

For it to work, you only need to put down votes for weight 1 , and votes against weight -1 .

 @post.upvote_from @user2, :vote_weight => 1 @post.downvote_from @user2, :vote_weight => -1 

Redundancy is formed, because the weights of the votes and their nature (for / against) are stored separately, but this is the problem of the heme as a whole: it tries to be as general as possible. That which is not used becomes useless redundancy. If you do not like it, you can:

  • Abandon the mechanics of the heme downvote, use the same voices of different weights and use the neutral helper (which generates the votes for , but it does not soar):

     @post.vote_by :voter => @user3, :vote_weight => (positive? 1 : -1) 
  • Discard the scales, use the sort by cached_votes_up - cached_votes_down , and not forget the functional index (or at least its surrogate in the form of a column and triggers) by it, so as not to count
  • Discard a heme, write a vote yourself
  • thanks, it looks like it will be easier and faster to write your voting license than to remake this gem) - Maxim Cherevatov
  • @MaximCherevatov is generally a simple thing. But in geme, the not very pleasant (albeit simple) task of caching the sum of weights has already been solved. Therefore, it makes sense to use the gem. - D-side