Rails model related to two models with a common grandparent...how to create a validation and factory?

24 Views Asked by At

I have a Submission model that belongs_to two different models: Student and Quiz.

Student and Quiz each individually belong_to a Course.

When a student sends a Submission for a quiz, it is assumed that the Quiz must be for the same Course that the Student is in. I want to write a validation for that.

First question: How can I write a validation to ensure that two related records (Student and Quiz) have the same, common parent?

Second question: How can I make a Submission factory that, when given no arguments, will create a Submission that passes that validation?

2

There are 2 best solutions below

0
David Hempy On

For the model validation, I used:

class Submission < ApplicationRecord
  belongs_to :student
  belongs_to :quiz
  
  validate :same_course

  def same_course
    if quiz.course != student.course
      errors.add(:quiz, "must be for the student's course")
    end
  end
end

Is that reasonable? Is there a more Rails-y way to express that?

0
David Hempy On

For the factory,

FactoryBot.define do
  factory :submission do
    transient do
      course { create :course }
    end

    student { create :student, course: course }
    quiz { create :quiz, course: course }
  end
end

This lets me create a submission without setting up any other records:

FactoryBot.create :submission

If I already have a course in hand, I can use that instead:

FactoryBot.create :submission, course: my_course

I can also pass in student and/or quiz, of course...although then the caller takes on the common-course-parent responsibility.

This has the sub-optimal side effect of creating a course record when you build :submission...but I can live with that.