Acts As Voteable Rails Plugin

24
Jun
13

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: , , , , , ,

Enjoy. Share. Be Happy.
  • Digg
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • BlinkList
  • MySpace
  • Netvouz
  • NewsVine
  • StumbleUpon
  • TwitThis
Filed under: Ruby, TechKnow
13 Comments

13 Comments

  1. Lawrence
    1:32 pm on March 30th, 2007

    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.

  2. TechKnow
    10:23 am on April 4th, 2007

    @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…

  3. Daniel Fischer
    7:50 pm on April 11th, 2007

    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?

  4. AMD
    11:47 am on April 18th, 2007

    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

  5. Rick Branson
    9:07 pm on May 16th, 2007

    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
    
  6. dMix
    5:06 pm on June 5th, 2007

    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

  7. Zach Brock
    2:54 pm on July 13th, 2007

    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…

  8. dict
    12:45 pm on August 1st, 2007

    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?

  9. Ramon Tayag
    4:04 am on February 26th, 2008

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

  10. Peter Jackson
    4:42 pm on July 13th, 2008

    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.

  11. Lukas
    8:36 am on October 4th, 2008

    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.

  12. Akhil Bansal
    2:31 am on November 14th, 2008

    @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.

Leave a comment

RSS feed for comments on this post