2

I have a model that has a uniqueness validation on it something like:

class CurriculumRequirement < ActiveRecord::Base

  belongs_to :student

  belongs_to :curriculum_sequence

  validates :student_id,
    uniqueness: { scope: [:curriculum_sequence_id] }
end 

The problem is that somehow duplicate records are being inserted into my database despite this validation. The place in which adding these records happens in a sidekiq background worker:

student.curriculum_requirements.where(curriculum_sequence: sequence).first_or_create

I think that what is happening is that 2 or more workers are executing the same code, and saving the record. Is there a way to put a lock or something on this record so that I don't get duplicates?

Kyle Decot
  • 20,715
  • 39
  • 142
  • 263
  • 1
    `sidekiq background worker` yes, this happens when it works in a few threads. You should include some locker, or setup sidekiq to work in one thread. – zishe May 05 '14 at 13:47
  • In case of locker you could do `Model.transaction { ... }` [link](http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html). Let me khow if it helps, i post it as an answer. – zishe May 05 '14 at 13:49
  • There are also some info on [sidekiq docs](https://github.com/mperham/sidekiq/wiki/Middleware) but i think you can avoid this. Transaction should be enough. – zishe May 05 '14 at 13:53
  • 1
    Why don't use a database unique constraint? – mdesantis May 05 '14 at 15:11

1 Answers1

7

Rails cannot guarantee uniqueness. You need to create a unique index on the table on [curriculum_sequence_id, student_id] in the database.

Mike Perham
  • 21,300
  • 6
  • 59
  • 61
  • 1
    Creating an index of this kind with already populated duplicated data might lead into trouble. Please see this topic: http://stackoverflow.com/questions/14752366/rails-unique-index-on-multiple-columns-fails-sqlite3 – sequielo Aug 07 '15 at 03:00