ryanto/acts_as_votable

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

  1. Add a unique key in votes table.
  2. 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?