Reputation: 13548
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
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
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
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