Newer
Older
dmpopidor / app / models / section.rb
# frozen_string_literal: true
# == Schema Information
#
# Table name: sections
#
#  id             :integer          not null, primary key
#  title          :string
#  description    :text
#  number         :integer
#  created_at     :datetime
#  updated_at     :datetime
#  phase_id       :integer
#  modifiable     :boolean
#  versionable_id :string(36)
#
# Indexes
#
#  index_sections_on_versionable_id  (versionable_id)
#  sections_phase_id_idx             (phase_id)
#

class Section < ActiveRecord::Base

  include ValidationMessages
  include ValidationValues
  include ActsAsSortable
  include VersionableModel


  # ================
  # = Associations =
  # ================

  belongs_to :phase
  belongs_to :organisation
  has_many :questions, dependent: :destroy
  has_one :template, through: :phase

  # ===============
  # = Validations =
  # ===============

  validates :phase, presence: { message: PRESENCE_MESSAGE }

  validates :title, presence: { message: PRESENCE_MESSAGE }

  # validates :description, presence: { message: PRESENCE_MESSAGE }

  validates :number, presence: { message: PRESENCE_MESSAGE },
                     uniqueness: { scope: :phase_id,
                                   message: UNIQUENESS_MESSAGE }

  validates :modifiable, inclusion: { in: BOOLEAN_VALUES,
                                      message: INCLUSION_MESSAGE }

  # =============
  # = Callbacks =
  # =============

  # TODO: Move this down to DB constraints
  before_validation :set_modifiable

  before_validation :set_number, if: :phase_id_changed?

  # =====================
  # = Nested Attributes =
  # =====================

  accepts_nested_attributes_for :questions,
    reject_if: -> (a) { a[:text].blank? },
    allow_destroy: true

  # ==========
  # = Scopes =
  # ==========

  # The sections for this Phase that have been added by the admin
  #
  # Returns ActiveRecord::Relation
  scope :modifiable, -> { where(modifiable: true) }

  # The sections for this Phase that were part of the original Template
  #
  # Returns ActiveRecord::Relation
  scope :not_modifiable, -> { where(modifiable: false) }

  # ===========================
  # = Public instance methods =
  # ===========================

  # The title of the Section
  #
  # Returns String
  def to_s
    "#{title}"
  end

  # Returns the number of answered questions for a given plan
  def num_answered_questions(plan)
    return 0 if plan.nil?

    answered = plan.answers.select do |answer|
      answer.answered? && questions.include?(answer.question)
    end
    answered.length
  end

  def deep_copy(**options)
    copy = self.dup
    copy.modifiable = options.fetch(:modifiable, self.modifiable)
    copy.phase_id = options.fetch(:phase_id, nil)
    copy.save!(validate: false)  if options.fetch(:save, false)
    options[:section_id] = copy.id
    self.questions.map { |question| copy.questions << question.deep_copy(options) }
    copy
  end

  # Can't be modified as it was duplicatd over from another Phase.
  def unmodifiable?
    !modifiable?
  end

  private

  # ============================
  # = Private instance methods =
  # ============================

  def set_modifiable
    self.modifiable = true if modifiable.nil?
  end

  def set_number
    return if phase.nil?
    self.number = phase.sections.where.not(id: id).maximum(:number).to_i + 1
  end

end