# 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