Justin Meltzer
Justin Meltzer

Reputation: 13548

Fix voting mechanism

I've implemented an up/down voting system that updates with ajax in my Ruby on Rails app. The buttons call the create method, a vote is inserted into the database, and the vote sum is calculated.

However, as of now, a user can upvote or downvote as many times as he or she would like. I want the voting to be like what we see here on StackOverflow, where a user can only vote up or down once, and the votes can be undone. How do I construct the logic for this?

Upvotes: 0

Views: 178

Answers (3)

Jesse Wolgamott
Jesse Wolgamott

Reputation: 40277

class Vote < ActiveRecord::Base
  belongs_to :question
  belongs_to :user

  validates_uniqueness_of :user_id, :scope=>question_id    
end

http://ar.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M000086

Your controller will return errors if you attempt to vote more than once. Have the UI delete the vote if you down a vote you've voted for.

Upvotes: 0

Victor Blaga
Victor Blaga

Reputation: 1862

I think you have a little more work to do. You should add to your model a many to many relationship between questions and users, in which you remember which user voted for which question and in which way(up or down). After that, when you render the question on the screen, you should select from that table the votes of the current user related to the question displayed.

When a user votes for a question you should add a record to the corresponding table.Also, when displaying the question, If the user has upvoted(downvoted), then you should style the upvote(downvote) link acoordingly. And if a user tries to vote again, you can check it before registering the vote in the database if the user already voted.

Maybe this is not the fastest way to do this kind of thing, but it gives you the most control (you can later display a detailed statistic about the voting style of a certain user, date and time at which the vote was casted, you can impose a limit to the number of votes a user can cast per day and so on...)

Upvotes: 0

Fareesh Vijayarangam
Fareesh Vijayarangam

Reputation: 5052

I'd recommend the acts_as_rateable gem, it's what I've been using for this sort of requirement for multiple websites. Does the job perfectly.

If you'd rather implement this yourself, your Rating model should have a user_id and be polymorphic so as to attach itself to whatever models you'd like to rate. Then you can simply code your AJAX controller to reject duplicate votes. At the front end, Javascript that removes the link functionality from the existing upvote/downvote should be implemented for good UX.

Upvotes: 1

Related Questions