Duplicates (race condition)
Opened this issue · 8 comments
Hi!
In my project users votes every day a lot (about ~5000 votes). User can voted for post only one time.
So, I have a simple code
@post.liked_by current_user unless current_user.voted_for? @post
But. I've find duplicates in votes table. One user voted two or more times for the same post.
I think it's happened when the server is overloaded and user send two or more times one http request in a short time.
How to prevent this? I think about
- Add a unique key in votes table.
- Get unique by user count votes for post (but I don't know how), some like
@post.votes_for.up.unique_by(User)
Could throw the vote in a background job and put a delay on it for a second.
Edit: really hacky but it'd do the job.
Maybe just disable the vote button with js when clicked.
@floydback You will definitely need a unique key if your business needs the user to vote only once. You should add a database constraint + rails validations of course and handle the user already voted scenario in you client.
@laertispappas Yes!
I relied on the fact that the unique key was added during installation
generate acts_as_votable:migration
@floydback I am not sure I do understand you. At the time being as far as I know and based on the migration template no constraint is added. I think there should be one since it doesn't make sense to have multiple votes per option.
@laertispappas Yes you are right. I have added a unique key to DB manually and it's work. Sorry for my English. All I want to say is when I installed this gem I expected migration file has some code like this:
add_index :votes, [:voter_id, :voter_type, :votable_id, :votable_type], unique: true
Maybe it would be nice to add in gem migration file
@floydback Agree with you but this depends on the application. Maybe there are applications that do need to have multiple votes (although I can't find a use case). +1 for your suggestion.
By the way is you're application public? Could I have a look since I am interested?