Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Act_As_Votable with Reddit style weighting algorithm in Rails

I am creating a rails app that has a User and Post model that implements the Act_As_Votable gem.

I want users to be able to upvote and downvote posts, but also want to rank and sort posts by a weighted_score algorithm that takes into account the number of upvotes, downvotes, and time the post was created.

My weighted_score algorithm is taken from Reddit and better described here.

My Post Model:

class Post < ActiveRecord::Base
  belongs_to :user
  acts_as_votable

  # Raw scores are = upvotes - downvotes
  def raw_score
    return self.upvotes.size - self.downvotes.size
  end

  def weighted_score
    raw_score = self.raw_score
    order = Math.log([raw_score.abs, 1].max, 10)
    if raw_score > 0
        sign = 1
    elsif raw_score < 0
        sign = -1
    else
        sign = 0
    end
    seconds = self.created_at.to_i - 1134028003
    return ((order + sign * seconds / 45000)*7).ceil / 7.0
  end
end

I want to use the Acts_As_Voteable gem because it supports caching which may decrease the number of hard disk writes and save time. Currently the weight_score of a post can be calculated on the fly but is not saved in the database, meaning I cannot do database sorts on posts with the highest weighted_score.

If I created a column in the post model I would have to update the posts table every time a user voted on a post, which defeats the purpose of using the Acts_As_Tagable gem (as I don't take advantage of its caching ability).

So I want to add a column to the votes table to store the weighted_score (which will then be calculated every time the post is voted on), as well as a method to the Votes model to calculate this score, however the gem does not provide a model when I run its generator. It only creates a votes table which I do not know how to access without a model.

Any help on how I can add such a weighted_score column and method to the votes model, or on how to achieve efficiently storing the weighted score of a post in a different manner is appreciated.

like image 297
steve Avatar asked Sep 29 '13 00:09

steve


2 Answers

acts_as_voteable adds methods to your model to access the votes http://juixe.com/techknow/index.php/2006/06/24/acts-as-voteable-rails-plugin/

positiveVoteCount = post.votes_for
negativeVoteCount = post.votes_against
totalVoteCount = post.votes_count

If you want to add a column, you can run a migration as normal on the table it creates. It also does appear to create a Vote model http://juixe.com/svn/acts_as_voteable/lib/vote.rb

like image 78
bridiver Avatar answered Oct 31 '22 16:10

bridiver


I would add the weighted_score column to your Post model and handle updating via callback. For instance:

class Post < ActiveRecord::Base

   #...

   before_save :update_weighted_score

   #...

   def update_weighted_score
     # check if some relevant variables have changed first, for example
     if cached_votes_total.changed?
        # do maths
        weighted_score = blah
     end 
   end
like image 34
Justin M Avatar answered Oct 31 '22 16:10

Justin M