Acts As Voteable Rails Plugin

Right on the heels of my release of acts_as_commentable, I am now making available a acts_as_voteable Ruby on Rails plugin. The Acts As Voteable plugin allows for model to be voted on by users.

To install this plugin run the following command:

script/plugin install http://juixe.com/svn/acts_as_voteable

The installation process will add several ruby files in the vendor/plugins directory. Create a new rails migration and cut and past the following self.up and self.down methods:

def self.up
  create_table :votes, :force => true do |t|
    t.column :vote, :boolean, :default => false
    t.column :created_at, :datetime, :null => false
    t.column :voteable_type, :string, :limit => 15,
      :default => "", :null => false
    t.column :voteable_id, :integer, :default => 0, :null => false
    t.column :user_id, :integer, :default => 0, :null => false
  end

  add_index :votes, ["user_id"], :name => "fk_votes_user"
end

def self.down
  drop_table :votes
end

Once you have installed the plugin you can start using it in your ActiveRecord models simply by calling the acts_as_voteable method.

class Post < ActiveRecord::Base
  acts_as_voteable
end

To cast a vote for a post you can do the following:

vote = Vote.new(:vote => true)
post = Post.find(params[:id])
post.votes << vote

ActiveRecord models that act as voteable can be queried for the positive votes, negative votes, and a total vote count by using the votes_for, votes_against, and votes_count methods respectively. Here is an example:

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

And because the Acts As Voteable plugin will add the has_many votes relationship to your model you can always get all the votes by using the votes property:

allVotes = post.votes

Technorati Tags: , , , , , ,

Related posts:

  1. Acts As Rateable Plugin
  2. Acts As Commentable Plugin
  3. Acts As Bookmarkable Plugin
  4. Acts As Versioned Plugin
  5. Acts As Blog Plugin
  6. Acts As Taggable Plugin


16 Responses to “Acts As Voteable Rails Plugin”

  • Lawrence Says:

    hey, lots of good stuff up here. sadly, I think the acts_as_voteable is broken. firstly the :submitted above should probably be :created_at as there is no submitted attribute in votes.

    also the voted_for and voted_against methods use TRUE and FALSE which errors in mySQL since mySQL uses int(1) for boolean types. is there a reason for this? i hate to see good plugins fall out of service.

  • TechKnow Says:

    @Lawrence – Thanks for bringing this to my attention. On MySQL 4.1.15, the vote column is a tinyint(1) and I get no error casting votes. I guess I could just use 1/0 instead of TRUE/FALSE to cast a vote. Let me read up on booleans on MySQL…

  • Daniel Fischer Says:

    Hey,

    Thanks for this plugin. There is one thing though, I would like to go for the route of allowing a user to vote from 1 through 5, instead of a basic vote for 1 point for e.g (that’s what your plugin currently acts as).

    How would I implement such a functionality? Could it be done with some slight modification to your plugin?

  • AMD Says:

    Hi, Thanks for the plugin, but for some reason it does not work for me. I have done what you have mentioned but it does not work and does not recognize the acts_as_voteable class or method.

    Please tell me how i can fix this.

    I’m using instantrails version 1.7

  • Rick Branson Says:

    I had a 1 N database problem with using acts_as_voteable when applied to a list of comments. I solved this with some updated code. If you are including in the votes table correctly, this will yield 0 extra database hits and hopefully squeeze out some extra performance.

    def votes_for
      votes_with_vote_of true
    end
    
    def votes_against
      votes_with_vote_of false
    end
    
    def votes_with_vote_of(vote)
      count = 0
      self.votes.each { |v|
        count  = 1 if v.vote == vote
      }
      count
    end
    
  • dMix Says:

    I have no been able to get a validation working with act_as_voteable

    How would I handle checking that the user_id, voteable_id, and vote are unique so the same person cant vote twice on the same post?

    I’ve tried putting “validates_uniquness_of” everywhere but its not working. Under the Post.rb its not validating but the vote is still being entered in the db.

    thanks
    Dan
    lifedmedia [at] gmail [dot] com

  • Zach Brock Says:

    I had the same issue as Dan, but I solved it by creating a new instance method.

    Just stick this under module InstanceMethods

    def vote (value, user)
      if user
        self.votes.each { |v|
          if user.id == v.user_id
            if v.vote == value
              return false
            else
              v.update_attribute(:vote, value)
              return true
            end
          end
        }
        self.votes  value, :user_id => user.id)
        return true
      end
    end
    

    To use it just call rated_item.vote value, user for instance: ad.vote true, user

    One quick caveat, you need to pass it actual boolean values or the comparison doesn’t work (at least with MySQL). So I have

    vote_value = false
    vote_value = true if params[:vote] == 'true'
    ad.vote vote_value, user
    

    in my controller. Hope this helps someone…

  • dict Says:

    Is a reputation system planned (i.e. each vote can have a weight based on the user that expressed it)?

    If not, any idea on how it should be implemented?

    Keeping the reputation count in User can be expensive when retrieving the vote count for a voteable (each vote would have to be multiplied by the reputation every time), but storing the reputation in the vote it’s not right because it varies with time.

    What do you think?

  • Ramon Tayag Says:

    It’s been a while since you’ve made changes.. but I was wondering, is there a “neutral” vote?

  • Announcing VoteFu | Pete On Rails Says:

    [...] is a voting mixin that allows you to extend your models to vote on one another. Largely based on Cosmin Radoi’s acts_as_voteable plugin, VoteFu adds named_scope support, a set of generators to make using the plugin easier, a [...]

  • Peter Jackson Says:

    I’ve added some functionality to this plugin, updated it to use named_scopes, the polymorphic keyword, and a couple other goodies.

    I’m planning to add ranged voting (configurable as 1..10, etc) and karma-weighted voting as well.

    Not sure if acts_as_voteable is still being maintained. If it is, I’m happy to fold my changes into the main project.

    Otherwise, you can see my enhancements on GitHub, Vote Fu.

  • Lukas Says:

    Hello, you have an error in the module acts_as_voteable.rb:

    on line 12:

    :dependent => :true

    On rails 2.1.1 :dependent => :true raises a fatal error. You can change for :nullify with the same effects to correct this error.

    Regards.

  • Akhil Bansal Says:

    @Lukas: you just need to edit lib/acts_as_votable.rb under plugin directory. And change :dependent=>true to :dependent=>:destroy. it will work fine.

  • Steve Eppley Says:

    I’m writing to ask you to rename this plugin. Its name is too generic; voting can comprise many other kinds of activity besides user ratings. (Traditionally, voting refers to a group choosing from a set of alternatives, a.k.a. candidates. There’s a rich body of academic literature known as “social choice theory.”) Perhaps acts_as_rateable would be a more appropriate name? Then the name acts_as_voteable could be reserved for a plugin that handles other kinds of voting.
    The plugin for voting that I hope to find (or develop myself) would be similar to acts_as_list, in that it would facilitate allowing the voter to sort a collection of alternatives into his/her desired order of preference. It would differ from acts_as_list–assuming my understanding of acts_as_list is correct; I’m new to Rails–in that a voter’s order of preference may have more than one alternative per position. (Known as a “nonlinear” or “nonstrict” or “weak” ordering.) That would allow the voter to express indifference between those alternatives. There are several reasons to allow expression of indifference: (1) A voter may sincerely be indifferent between some alternatives. (2) The list of alternatives when initially presented to the voter should not necessarily be ordered since a pre-ordered ballot could affect the votes, so before the voter sorts the alternatives they would initially all appear at the same position. (3) In some elections there could be so many alternatives that it would be too tedious for voters to order them all; it would save time if the voter may leave some alternatives “unranked,” which would be treated as if the voter had ranked them together at the bottommost position. (4) It may be desirable to allow voters to strategically vote “insincere” indifference between some alternatives. (If you’re curious why that can be desirable, you can google the “Minimal Defense” criterion or the “Strong Defensive Strategy Criterion.”)
    The reason I’m looking for such a plugin is because I want to construct an online voting server that implements the Maximize Affirmed Majorities (MAM) voting method and (if I have time) the Voting for a Published Ranking (VPR) voting method. If you want more details, feel free to ask me.
    Thanks for considering this, and best wishes,
    Steve

  • RubyWorm Says:

    @Steve Eppley =) seriously chill! and get a life ;)

    @TechKnow great blog man, and awesome plugins many thanks :)

  • 0x4a6f4672 Says:

    With the newest version of rails (2.3.5) there will be the same error as in the “Acts as Rateable” plugin: “The :dependent option expects either :destroy, :delete_all, or :nullify (true)”

    As the others already remarked, :dependent => :true must be changed in :dependent => :destroy to make it work (line 12 in vendor/plugins/acts_as_voteable/lib/acts_as_voteable.rb).

Leave a Reply