-
Notifications
You must be signed in to change notification settings - Fork 118
Expand file tree
/
Copy pathsection.rb
More file actions
135 lines (109 loc) · 3.43 KB
/
section.rb
File metadata and controls
135 lines (109 loc) · 3.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# frozen_string_literal: true
# == Schema Information
#
# Table name: sections
#
# id :integer not null, primary key
# description :text
# modifiable :boolean
# number :integer
# title :string
# created_at :datetime
# updated_at :datetime
# phase_id :integer
# versionable_id :string(36)
#
# Indexes
#
# index_sections_on_phase_id (phase_id)
# index_sections_on_versionable_id (versionable_id)
#
# Foreign Keys
#
# fk_rails_... (phase_id => phases.id)
#
# Object that represents a Template section
class Section < ApplicationRecord
include ActsAsSortable
include VersionableModel
# Sort order: Number ASC
default_scope { order(number: :asc) }
attribute :modifiable, :boolean, default: true
# ================
# = Associations =
# ================
belongs_to :phase
belongs_to :organisation, optional: true
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 }
# =========================
# = Custom Accessor Logic =
# =========================
# ensure the number gets set to a valid-value
def phase_id=(value)
phase = Phase.where(id: value).first
self.number = (phase.sections.where.not(id: id).maximum(:number).to_i + 1) if phase.present?
super
end
# =====================
# = 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.to_s
end
# Returns the number of answered questions for a given plan
def num_answered_questions(plan)
answered_questions(plan).count(&:answered?)
end
# Returns an array of answered questions for a given plan
def answered_questions(plan)
return [] if plan.nil?
plan.answers
.select { |answer| question_ids.include?(answer.question_id) }
.to_a
end
def deep_copy(**options)
copy = dup
copy.modifiable = options.fetch(:modifiable, modifiable)
copy.phase_id = options.fetch(:phase_id, nil)
copy.save!(validate: false) if options.fetch(:save, false)
options[:section_id] = copy.id
questions.map { |question| copy.questions << question.deep_copy(**options) }
copy
end
# Can't be modified as it was duplicated over from another Phase.
def unmodifiable?
!modifiable?
end
end