chore: init commit
in worker.../repo/GITFOLDER.zip is the .git folder.
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Represents a student's enrollment in a classroom, supporting multiple
|
||||
# enrollments over time with historical tracking.
|
||||
#
|
||||
# A student can have multiple enrollment records for the same classroom
|
||||
# (e.g., enrolled in Fall 2023, then again in Spring 2024), and can be
|
||||
# enrolled in multiple classrooms simultaneously.
|
||||
#
|
||||
# @example Find a student's current enrollments
|
||||
# student.classroom_enrollments.current
|
||||
#
|
||||
# @example Find a student's enrollment history
|
||||
# student.classroom_enrollments.historical
|
||||
#
|
||||
# @example Get a student's primary classroom
|
||||
# student.primary_enrollment&.classroom
|
||||
class ClassroomEnrollment < ApplicationRecord
|
||||
belongs_to :student, class_name: "Student"
|
||||
belongs_to :classroom
|
||||
|
||||
validates :enrolled_at, presence: true
|
||||
validate :unenrolled_at_after_enrolled_at
|
||||
validate :only_one_primary_per_student, if: :primary?
|
||||
|
||||
scope :current, -> { where(unenrolled_at: nil) }
|
||||
scope :historical, -> { where.not(unenrolled_at: nil) }
|
||||
scope :primary_enrollment, -> { where(primary: true) }
|
||||
scope :for_student, ->(student) { where(student: student) }
|
||||
scope :for_classroom, ->(classroom) { where(classroom: classroom) }
|
||||
|
||||
# Mark this enrollment as the primary enrollment for the student
|
||||
# and demote any other primary enrollments
|
||||
#
|
||||
# @return [self]
|
||||
def make_primary!
|
||||
transaction do
|
||||
ClassroomEnrollment.where(student: student, primary: true)
|
||||
.where.not(id: id)
|
||||
.find_each { |enrollment| enrollment.update!(primary: false) }
|
||||
update!(primary: true)
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
# Unenroll the student from this classroom
|
||||
#
|
||||
# @param at [DateTime] when the student was unenrolled (defaults to now)
|
||||
# @return [self]
|
||||
def unenroll!(at: Time.current)
|
||||
update!(unenrolled_at: at, primary: false)
|
||||
self
|
||||
end
|
||||
|
||||
# Check if this enrollment is currently active
|
||||
#
|
||||
# @return [Boolean]
|
||||
def current?
|
||||
unenrolled_at.nil?
|
||||
end
|
||||
|
||||
# Check if this enrollment is historical (no longer active)
|
||||
#
|
||||
# @return [Boolean]
|
||||
def historical?
|
||||
!current?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def unenrolled_at_after_enrolled_at
|
||||
return if unenrolled_at.blank? || enrolled_at.blank?
|
||||
return if unenrolled_at >= enrolled_at
|
||||
|
||||
errors.add(:unenrolled_at, "must be after enrolled_at")
|
||||
end
|
||||
|
||||
def only_one_primary_per_student
|
||||
return if student_id.blank?
|
||||
|
||||
existing = ClassroomEnrollment.where(student_id: student_id, primary: true)
|
||||
.where.not(id: id)
|
||||
.exists?
|
||||
|
||||
errors.add(:primary, "student can only have one primary enrollment") if existing
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user