Тест ограничения уникальности «многие ко многим» не работает - PullRequest
1 голос
/ 09 января 2012

У меня есть отношение многие ко многим с таблицей соединений в моем приложении Rails.Я использую has_many: через идиому в моих моделях.Для простоты, давайте назовем мой ученик первого класса, мой курс второго класса и класс регистрации Enrollment (который содержит поля student_id и course_id).Я хочу убедиться, что данный Студент связан с данным Курсом не более одного раза (т. Е. Кортеж {student_id, course_id} должен быть уникальным в таблице регистрации).

Итак, у меня есть миграция a, которая обеспечивает эту уникальность.

def change
  add_index :enrollments, [:student_id, :course_id], :unique => true
end

Кроме того, классы моей модели определены так:

class Student < ActiveRecord::Base
  has_many :enrollments  
  has_many :courses, :through => :enrollment

end

class Course < ActiveRecord::Base
  has_many :enrollments
  has_many :students, :through => :enrollment

end

class Enrollment < ActiveRecord::Base
  belongs_to :student
  belongs_to :course

  validates :student,    :presence => true
  validates :course,     :presence => true
  validates :student_id, :uniqueness => {:scope => :course_id}

end

В консоли rails,Я могу сделать следующее:

student = Student.first
course = Course.first
student.courses << course
#... succeeds
student.courses << course
#... appropriately fails and raises an ActiveRecord::RecordInvalid exception

В моем тесте RSpec я делаю то же самое, и я не получаю исключения со следующим кодом:

@student.courses << @course
expect { @student.courses << @course }.to raise_error(ActiveRecord::RecordInvalid)

И поэтому мой тест не пройдени отчеты:

expected ActiveRecord::RecordInvalid but nothing was raised

Что здесь происходит?Что я могу делать не так?Как мне это исправить?

Ответы [ 2 ]

1 голос
/ 14 февраля 2012

Rails использует проверку на уровне модели; если вы хотите провести строгую проверку на уникальность, вам нужно использовать уровень базы данных - например, внешние ключи. Но в этом случае вам нужно отлавливать исключения из коннектора базы данных. Это странно, потому что в моем коде (очень похожем на ваш) проверка уникальности вызывает исключение.

0 голосов
/ 12 января 2012

Здесь может произойти несколько вещей:

  1. @ курсы изменились между использованиями.
  2. @ student изменился между использованиями.

Используя let, вы защитите эти значения от изменения ожиданий.

let(:course) { Course.first }
let(:student) { Student.first }
subject{ student.courses << course << course }
it { should raise_error(ActiveRecord::RecordInvalid) }

Или, возможно, что-то не так с вашим кодом:)

...