BallotBox

The BallotBox gem enables visitors to vote for and against voteable objects

Install

gem 'ballot_box'

rails generate ballot_box:install

Usage

Use middleware with options: route and voteable_type

# Initialize BallotBox request manager and set its configurations.
config.app_middleware.use BallotBox::Manager do |config|
  config.routes = { "/posts/votes" => "Post" }
end

Set voteable model:

class Post < ActiveRecord::Base
  ballot_box :counter_cache => true,
             :strategies => [:authenticated],
             :place => :position,
             :scope => :group_id
end

Set votes sum column:

ballot_box :counter_cache => :rating, :strategies => [:authenticated]

Set place (position) column:

ballot_box :place => true, :counter_cache => true

or update place scope conditions:

ballot_box :counter_cache => :rating, 
           :place => "place"

def self.ballot_box_place_scope
  unscoped.order("rating DESC").where(:is_visible => true)
end

Update votes sum directly:

Post.ballot_box_update_votes!

or update votes sum only for one record:

@post.ballot_box_update_votes!

Update place directly for all scopes:

Post.ballot_box_update_place!

or update place only for one scope:

@post.ballot_box_update_place!

View (just send post request to configure route):

link_to 'Vote', "/posts/votes?id=#{@post.id}", :remote => true, :method => :post

Strategies

Strategy - is no more a simple validation at the object vote. Authenticated - check :voter attribute is not blank.

module BallotBox
  module Strategies
    class Authenticated < Base
      validates_presence_of :voter
    end
  end
end

Write your own strategies:

class MyCustomStrategy < BallotBox::Strategies::Base
  validate :check_visible, :check_unique_voter

  protected

    def check_visible
      errors.add(:voteable, :invalid) unless voteable.visible?
    end

    def check_unique_voter
      if vote.class.where(["voter_id = ?  AND voter_type = ?", vote.voter_id, vote.voter_type]).exists?
        errors.add(:voter, :taken)
      end
    end
end

class Post < ActiveRecord::Base
  ballot_box :strategies => [:authenticated, 'MyCustomStrategy']
end

Callbacks

Middleware callbacks:

BallotBox::Manager.before_vote do |env, vote|
  vote.voter = env['warden'].user
  #vote.errors.add(:voter, :empty)
end

BallotBox::Manager.after_vote do |env, vote|
  Rails.logger.info(vote.to_xml)
end

ActiveRecord callbacks:

class Post < ActiveRecord::Base
  ballot_box :counter_cache => true

  before_vote :method_before
  after_vote :method_after

  def method_before
    Rails.logger.info current_vote.to_xml
    # To terminate register vote, just return false
    # return false
  end

  def method_after

  end
end

This project rocks and uses MIT-LICENSE.