diff --git a/app/models/registration.rb b/app/models/registration.rb index 3ede8051b..6f6d2d310 100644 --- a/app/models/registration.rb +++ b/app/models/registration.rb @@ -24,6 +24,21 @@ class Registration < ApplicationRecord delegate :course, to: :exam delegate :term, to: :course + validates :user, uniqueness: { scope: :exam_version } + + # note: we are not sure whether the current reg will show up in the association, + # so this validation remains separate from the previous uniqueness check + validate :user_exam_uniqueness + def user_exam_uniqueness + other_reg_exists = + user + .registrations + .where(exam_version: exam.exam_versions) + .where.not(exam_version: exam_version) + .any? + errors.add(:user, 'already has a registration for another version of that exam') if other_reg_exists + end + def room_version_same_exam return unless room diff --git a/test/models/user_test.rb b/test/models/user_test.rb index 83cbe5453..8421daa6e 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -10,4 +10,21 @@ class UserTest < ActiveSupport::TestCase test 'admin factory builds admins' do assert build(:admin).admin? end + + test 'cannot create two registrations for the same ExamVersion-User pair' do + r1 = create(:registration) + r2 = build(:registration, user: r1.user, exam_version: r1.exam_version) + assert_not r2.valid? + assert_match(/has already been taken/, r2.errors.full_messages.to_sentence) + assert_not r2.save + end + + test 'cannot create two registrations for the same Exam-User pair' do + r1 = create(:registration) + second_version = create(:exam_version, exam: r1.exam) + r2 = build(:registration, user: r1.user, exam_version: second_version) + assert_not r2.valid? + assert_match(/has a registration for another version/, r2.errors.full_messages.to_sentence) + assert_not r2.save + end end