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: ruby, rails, ruby on rails, plugin, rails plugin, acts_as_commentable, acts_as_voteable
Related posts:
15 Comments
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.
@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…
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?
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
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 endI 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
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 endTo 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
in my controller. Hope this helps someone…
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?
It’s been a while since you’ve made changes.. but I was wondering, is there a “neutral” vote?
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.
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.
@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.
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
@Steve Eppley =) seriously chill! and get a life ;)
@TechKnow great blog man, and awesome plugins many thanks :)
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).
One Trackback
[...] 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 [...]