Voteable Mongoid

Voteable Mongoid allows you to make your Mongoid::Document objects voteable (up or down). For instance, in a forum, a user can vote up (or down) on a post or a comment.

Initial idea is based on cookbook.mongodb.org/patterns/votes

Voteable Mongoid is built for speed. It uses only one database request per collection to validate data, update data, and get updated data.

Sample app at github.com/vinova/simple_qa

Installation

Rails 3.0.x

To install the gem, add this to your Gemfile

gem 'voteable_mongoid'

After that, remember to run “bundle install”

Usage

Making Post and Comment voteable, User being the voter

post.rb

class Post
  include Mongoid::Document
  include Mongoid::Voteable

  # set points for each vote
  voteable self, :up => +1, :down => -1

  references_many :comments
end

comment.rb

require 'post'

class Comment
  include Mongoid::Document
  include Mongoid::Voteable

  referenced_in :post

  voteable self, :up => +1, :down => -3

  # each vote on a comment can affect votes count and point of the related post as well
  voteable Post, :up => +2, :down => -1
end

user.rb

class User
  include Mongoid::Document
  include Mongoid::Voter
end

Making a vote

@user.vote(@post, :up)

Is equivalent to

@user.vote(:votee => @post, :value => :up)
@post.vote(:voter => @user, :value => :up)

In case you don't need to init voter and / or votee objects you can

@user.vote(:votee_type => 'Post', :votee_id => post_id, :value => :down)
@post.vote(:voter_id => user_id, :value => :up)
Post.vote(:voter_id => user_id, :votee_id => post_id, :value => :up)

Undo a vote

@user.unvote(@comment)

If have voter_id, votee_id and vote value you don't need to init voter and votee objects (suitable for API calls)

New vote

Post.vote(:voter_id => user_id, :votee_id => post_id, :value => :up)

Re-vote

Post.vote(:voter_id => user_id, :votee_id => post_id, :value => :up, :revote => true)

Un-vote

Post.vote(:voter_id => user_id, :votee_id => post_id, :value => :up, :unvote => true)

In-case you need updated votes data, add :return_votes => true

votes = Post.vote(:voter_id => user_id, :votee_id => post_id, :value => :up, :return_votes => true)
votes['up']         # => up_voter_ids who voted up
votes['down']       # => down_voter_ids who voted down
votes['up_count']   # => number of up votes (votes_voter_ids.length)
votes['down_count'] # => number of down votes (down_voter_ids.length)
votes['count']      # => number of votes (up_count + down_count)
votes['point']      # => total vote points

Getting vote_value

@user.vote_value(@post)
@user.vote_value(:class_type => 'Post', :votee_id => post_id)
@post.vote_value(@user)
@post.vote_value(user_id)

Check if voted?

@user.voted?(@post)
@user.voted?(:class_type => 'Post', :votee_id => post_id)
@post.voted_by?(@user)
@post.voted_by?(user_id)

Getting votes counts and points

puts @post.votes_point
puts @post.votes_count
puts @post.up_votes_count
puts @post.down_votes_count

Getting the list of voted objects of a class

Post.voted_by(@user)
Post.up_voted_by(@user)
Post.down_voted_by(@user)

Utilities

Re-generate counters and vote points in case you change :up / :down vote points

Rails

rake db:mongoid:voteable:remake_stats

Ruby

Mongoid::Voteable::Tasks.remake_stats

Set counters and point to 0 for uninitialized voteable objects in order sort and query

Rails

rake db:mongoid:voteable:init_stats

Ruby

Mongoid::Voteable::Tasks::init_stats

Migrate from version < 0.7.0

Rails

rake db:mongoid:voteable:migrate_old_votes

Ruby

Mongoid::Voteable::Tasks.migrate_old_votes

Credits

  • Alex Nguyen (alex@vinova.sg) - Author

  • Stefan Nguyen (stefan@vinova.sg) - Unvoting

Copyright © 2010-2011 Vinova Pte Ltd (vinova.sg)

Licensed under the MIT license.