Class: CourseExam

Inherits:
ApplicationRecord show all
Defined in:
app/models/course_exam.rb

Overview

== Schema Information

Table name: course_exams
Database name: primary

id :bigint not null, primary key
attainable_maximum :integer
position :integer
score :integer
state :string
created_at :datetime not null
updated_at :datetime not null
course_enrollment_id :integer
topic_exam_id :integer

Indexes

index_course_exams_on_course_enrollment_id (course_enrollment_id)

Foreign Keys

fk_rails_... (course_enrollment_id => course_enrollments.id)

A learner's attempt at a course's final exam. Created when the learner
requests the exam (position = attempt number), it carries their answers as
CustomerTopic copies and is graded by Grader. Lifecycle:
new → in_progress → passed/failed (or cancelled by staff); passing
completes the parent CourseEnrollment and triggers the learner/staff
notifications, failing only notifies — retakes are unlimited.

Defined Under Namespace

Classes: Grader, InitializeTopics

Constant Summary

Constants included from Models::Schedulable

Models::Schedulable::SIMPLE_FORM_OPTIONS

Belongs to collapse

Has many collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Models::Schedulable

config

Methods included from Models::AfterCommittable

#after_commit

Methods included from Models::EventPublishable

#publish_event

Class Method Details

.activeActiveRecord::Relation<CourseExam>

A relation of CourseExams that are active. Active Record Scope

Returns:

See Also:



46
# File 'app/models/course_exam.rb', line 46

scope :active, -> { where(state: 'in_progress') }

.passedActiveRecord::Relation<CourseExam>

A relation of CourseExams that are passed. Active Record Scope

Returns:

See Also:



45
# File 'app/models/course_exam.rb', line 45

scope :passed, -> { where(state: 'passed') }

.sortedActiveRecord::Relation<CourseExam>

A relation of CourseExams that are sorted. Active Record Scope

Returns:

See Also:



47
# File 'app/models/course_exam.rb', line 47

scope :sorted, -> { order(:position) }

Instance Method Details

#course_enrollmentCourseEnrollment

The enrollment this attempt belongs to.



34
# File 'app/models/course_exam.rb', line 34

belongs_to :course_enrollment, optional: true

#customer_topicsActiveRecord::Relation<CustomerTopic>

The learner's per-question answer copies for this attempt.

Returns:

See Also:



39
# File 'app/models/course_exam.rb', line 39

has_many :customer_topics, -> { order(:position) }, inverse_of: :course_exam

#cutoff_markInteger

The minimum score needed to pass, from the exam definition.

Returns:

  • (Integer)


104
105
106
# File 'app/models/course_exam.rb', line 104

def cutoff_mark
  topic_exam.min_score_to_pass.to_i
end

#failed?Boolean

Whether the attempt was graded below the pass threshold.

Returns:

  • (Boolean)


90
91
92
# File 'app/models/course_exam.rb', line 90

def failed?
  state == 'failed'
end

#in_progress?Boolean

Whether the attempt is open (started but not yet graded).

Returns:

  • (Boolean)


83
84
85
# File 'app/models/course_exam.rb', line 83

def in_progress?
  state == 'in_progress'
end

#passed?Boolean

Whether the attempt was graded at or above the pass threshold.

Returns:

  • (Boolean)


97
98
99
# File 'app/models/course_exam.rb', line 97

def passed?
  state == 'passed'
end

#score_displayString?

Score alongside the attainable maximum, e.g. "12 of 15 (80%)" —
absolute points alone are meaningless once questions are added or
removed from the exam definition. Uses the maximum captured when the
attempt was created, ensuring it remains immutable even if the exam
definition changes.

Returns:

  • (String, nil)

    nil while the attempt is ungraded



115
116
117
118
119
120
121
122
# File 'app/models/course_exam.rb', line 115

def score_display
  return if score.nil?

  max = attainable_maximum.to_i
  return score.to_s unless max.positive?

  "#{score} of #{max} (#{score * 100 / max}%)"
end

#topic_examTopicExam

The exam definition (questions + pass threshold) being attempted.

Returns:

See Also:



36
# File 'app/models/course_exam.rb', line 36

belongs_to :topic_exam, optional: true