GAKUEngine/gaku

View on GitHub
core/app/models/gaku/exam_portion.rb

Summary

Maintainability
A
45 mins
Test Coverage
module Gaku
  class ExamPortion < ActiveRecord::Base
    include ActiveModel::Dirty

    attr_accessor :custom_errors

    belongs_to :exam, counter_cache: true
    belongs_to :grading_method, required: false

    has_many :exam_schedules
    has_many :exam_portion_scores
    has_many :attachments, as: :attachable
    has_many :attendances, as: :attendancable

    validates :name, presence: true

    validates :weight,
              numericality: { greater_than_or_equal_to: 0,
                              if: proc { |ep| ep.weight.present? } }

    validates :max_score, presence: true,
                          numericality: { greater_than_or_equal_to: 0 }

    before_create :proper_position
    before_create :init_weight
    after_destroy :refresh_positions

    before_update :weight_calculate
    before_save :sanitize_score_selection_options

    enum score_type: %i[score score_selection score_text]

    def to_s
      name
    end

    def correct_weight_with_error
      self.weight = weight_was
    end

    def weight_calculate
      if (exam.total_weight_except(self) + weight) > 100
        last = exam.exam_portions.last

        interval = weight - weight_was
        if self != last
          if interval <= last.weight
            last.update_attribute(:weight, last.weight - interval)
          else
            correct_weight_with_error
          end
        else
          correct_weight_with_error
        end

      end
    end

    def init_weight
      if weight.nil?
        other_ep = exam.exam_portions
        percentage = 100 / (other_ep.count + 1)
        self.weight = percentage
        other_ep.update_all weight: percentage
      end
    end

    def student_score(student)
      exam_portion_scores.where(student_id: student.id).first
    end

    private

    def sanitize_score_selection_options
      self.score_selection_options = score_selection_options.reject(&:blank?) if score_selection_options
    end

    def proper_position
      self.position = exam.exam_portions.count
    end

    def refresh_positions
      exam_portions = exam.exam_portions
      exam_portions.pluck(:id).each_with_index do |id, index|
        exam_portions.where(id: id).update_all(position: index)
      end
    end
  end
end