Class: Topic

Inherits:
ApplicationRecord show all
Extended by:
FriendlyId
Includes:
Models::Auditable, PgSearch::Model
Defined in:
app/models/topic.rb

Overview

== Schema Information

Table name: topics
Database name: primary

id :integer not null, primary key
applies_to_company :boolean default(FALSE)
applies_to_contact :boolean default(FALSE)
applies_to_employee :boolean default(FALSE)
contact_roles :string(255) is an Array
description :text
email_snippet :text
format :string
integer :integer is an Array
multiple_responses_allowed :boolean
position :integer
slug :string
state :string(255) not null
string :string(255) is an Array
title :string(255) not null
training_module :boolean default(FALSE), not null
created_at :datetime not null
updated_at :datetime not null
creator_id :integer
customer_filter_id :integer
survey_id :integer
topic_category_id :integer
topic_exam_id :integer
updater_id :integer

Indexes

idx_state_survey_id (state,survey_id)
idx_state_topic_category_id (state,topic_category_id)
index_topics_on_topic_exam_id (topic_exam_id)
topics_customer_filter_id_idx (customer_filter_id)
topics_topic_category_id_idx (topic_category_id)

Foreign Keys

fk_rails_... (topic_exam_id => topic_exams.id)
topics_customer_filter_id_fk (customer_filter_id => customer_filters.id)
topics_topic_category_id_fk (topic_category_id => topic_categories.id)

Constant Summary

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Constants included from Models::Schedulable

Models::Schedulable::SIMPLE_FORM_OPTIONS

Instance Attribute Summary collapse

Belongs to collapse

Methods included from Models::Auditable

#creator, #updater

Has many collapse

Has and belongs to many collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::Auditable

#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransortable_attributes, #to_relation

Methods included from Models::Schedulable

config

Methods included from Models::AfterCommittable

#after_commit

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#titleObject (readonly)



74
# File 'app/models/topic.rb', line 74

validates :title, presence: true, uniqueness: { scope: %i[topic_category_id survey_id] }, length: { maximum: 200 }

Class Method Details

.activeActiveRecord::Relation<Topic>

A relation of Topics that are active. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Topic>)

See Also:



104
# File 'app/models/topic.rb', line 104

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

.assigned_toActiveRecord::Relation<Topic>

A relation of Topics that are assigned to. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Topic>)

See Also:



128
# File 'app/models/topic.rb', line 128

scope :assigned_to, ->(party) { joins(:party_topics).where(party_topics: { party_id: party.id }) }

.for_audienceActiveRecord::Relation<Topic>

A relation of Topics that are for audience. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Topic>)

See Also:



119
120
121
122
123
124
125
126
# File 'app/models/topic.rb', line 119

scope :for_audience, ->(*audiences) {
  hsh_cnd = {
    'employees' => "topics.applies_to_employee = true",
    'contacts' => "topics.applies_to_contact = true",
    'companies' => "topics.applies_to_company = true"
  }.with_indifferent_access.slice(*audiences)
  where(hsh_cnd.values.join(' OR '))
}

.for_contact_roleActiveRecord::Relation<Topic>

A relation of Topics that are for contact role. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Topic>)

See Also:



111
# File 'app/models/topic.rb', line 111

scope :for_contact_role, ->(*roles) { where(applies_to_contact: true).where("? = ANY (contact_roles)", roles) }

.for_customer(customer) ⇒ Object



141
142
143
144
145
146
147
# File 'app/models/topic.rb', line 141

def self.for_customer(customer)
  customer_filter_ids = CustomerFilter::QueryBuilder.filter_ids_for_customer(customer) + [nil]
  Topic.active.sorted
       .where.any_of({ applies_to_company: true }, { applies_to_contact: true })
       .where(customer_filter_id: customer_filter_ids)
       .includes(:topic_category)
end

.for_customer_grouped(customer) ⇒ Object



137
138
139
# File 'app/models/topic.rb', line 137

def self.for_customer_grouped(customer)
  for_customer(customer).group_by(&:topic_category)
end

.for_employeeActiveRecord::Relation<Topic>

A relation of Topics that are for employee. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Topic>)

See Also:



113
114
115
116
117
# File 'app/models/topic.rb', line 113

scope :for_employee, ->(employee) {
  eager_load(:employee_topics)
    .where("party_topics.party_id = ? or party_topics.id is null", employee.id)
    .for_employee_role_ids(employee.role_ids)
}

.for_employee_grouped_by_category(employee) ⇒ Object



149
150
151
# File 'app/models/topic.rb', line 149

def self.for_employee_grouped_by_category(employee)
  for_employee(employee).sorted.group_by(&:topic_category)
end

.for_employee_role_idsActiveRecord::Relation<Topic>

A relation of Topics that are for employee role ids. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Topic>)

See Also:



106
107
108
109
# File 'app/models/topic.rb', line 106

scope :for_employee_role_ids, ->(*role_ids) {
  where(applies_to_employee: true)
    .where("NOT EXISTS(select 1 from roles_topics rt where rt.topic_id = topics.id) OR EXISTS(select 1 from roles_topics rt where rt.topic_id = topics.id AND rt.role_id IN (?))", [role_ids].flatten)
}

.format_select_optionsObject



157
158
159
# File 'app/models/topic.rb', line 157

def self.format_select_options
  [['Normal', 'normal'], ['Numeric horizontal', 'numeric_horizontal']]
end

.ransackable_scopes(_auth_object = nil) ⇒ Object



133
134
135
# File 'app/models/topic.rb', line 133

def self.ransackable_scopes(_auth_object = nil)
  %i[for_audience for_contact_role for_employee_role_ids keywords]
end

.select_options_with_categoriesObject



153
154
155
# File 'app/models/topic.rb', line 153

def self.select_options_with_categories
  Topic.joins(:topic_category).active.where(applies_to_employee: true).order(TopicCategory[:name], Topic[:title]).map { |t| ["#{t.topic_category.name} > #{t.title}", t.id] }
end

.sortedActiveRecord::Relation<Topic>

A relation of Topics that are sorted. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Topic>)

See Also:



100
101
102
103
# File 'app/models/topic.rb', line 100

scope :sorted, -> {
  joins(:topic_category)
    .order('topic_categories.position, topics.position, topics.title')
}

Instance Method Details

#applies_to_customer?(customer) ⇒ Boolean

Returns:

  • (Boolean)


165
166
167
168
169
170
171
# File 'app/models/topic.rb', line 165

def applies_to_customer?(customer)
  if customer_filter
    customer_filter.applies_to_customer?(customer)
  else
    true
  end
end

#applies_to_party?(party) ⇒ Boolean

Returns:

  • (Boolean)


227
228
229
230
# File 'app/models/topic.rb', line 227

def applies_to_party?(party)
  (applies_to_company? and party.is_a? Customer) or
    (applies_to_contact? and party.is_a? Contact)
end

#articlesActiveRecord::Relation<Article>

Returns:

  • (ActiveRecord::Relation<Article>)

See Also:



64
# File 'app/models/topic.rb', line 64

has_and_belongs_to_many :articles

#contact_training_topicsActiveRecord::Relation<ContactTrainingTopic>

Returns:

See Also:



62
# File 'app/models/topic.rb', line 62

has_many :contact_training_topics, inverse_of: :topic

#customer_filterCustomerFilter



54
# File 'app/models/topic.rb', line 54

belongs_to :customer_filter, inverse_of: :topics, optional: true

#customer_topic?Boolean

Returns:

  • (Boolean)


198
199
200
# File 'app/models/topic.rb', line 198

def customer_topic?
  applies_to_company || applies_to_contact
end

#customer_topicsActiveRecord::Relation<CustomerTopic>

Returns:

See Also:



61
# File 'app/models/topic.rb', line 61

has_many :customer_topics, inverse_of: :topic

#deep_dupObject



91
92
93
94
95
96
97
98
# File 'app/models/topic.rb', line 91

def deep_dup
  deep_clone(
    include: [:topic_responses],
    except: %i[created_at updated_at]
  ) do |_original, copy|
    copy.state = 'draft' if copy.is_a?(Topic)
  end
end

#employee_topic?Boolean

Returns:

  • (Boolean)


202
203
204
# File 'app/models/topic.rb', line 202

def employee_topic?
  applies_to_employee
end

#employee_topicsActiveRecord::Relation<EmployeeTopic>

Returns:

See Also:



60
# File 'app/models/topic.rb', line 60

has_many :employee_topics, inverse_of: :topic

#legacy_uploadsActiveRecord::Relation<Upload>

Returns:

  • (ActiveRecord::Relation<Upload>)

See Also:



65
# File 'app/models/topic.rb', line 65

has_and_belongs_to_many :legacy_uploads, class_name: 'Upload'

#multiple_responses?Boolean

Returns:

  • (Boolean)


236
237
238
# File 'app/models/topic.rb', line 236

def multiple_responses?
  topic_responses.where(TopicResponse[:score].gt(0))&.size&.> 1
end

#nextObject



232
233
234
# File 'app/models/topic.rb', line 232

def next
  topic_category.topics.order(:position).where(position: position + 1).first
end

#party_topicsActiveRecord::Relation<PartyTopic>

Returns:

See Also:



59
# File 'app/models/topic.rb', line 59

has_many :party_topics, inverse_of: :topic

#possible_eventsObject



173
174
175
# File 'app/models/topic.rb', line 173

def possible_events
  state_transitions.map(&:event).sort
end

#possible_events_for_selectObject



177
178
179
# File 'app/models/topic.rb', line 177

def possible_events_for_select
  possible_events.map { |evt| [evt.to_s.titleize, evt] }
end

#responses_listObject



206
207
208
# File 'app/models/topic.rb', line 206

def responses_list
  topic_responses.map(&:response).join(',') if topic_responses.present?
end

#responses_list=(new_tags) ⇒ Object



210
211
212
213
214
215
216
217
218
219
220
221
# File 'app/models/topic.rb', line 210

def responses_list=(new_tags)
  # split into array (comma and any spaces), ignore empties
  responses = process_tag_list(new_tags)
  valid_responses = []
  responses.each_with_index do |r, index|
    robj = topic_responses.where(TopicResponse[:response].matches(r)).first
    robj ||= topic_responses.build(response: r, active: true, position: index)
    valid_responses << robj
  end
  # Dump invalids
  (topic_responses.to_a - valid_responses).each(&:mark_for_destruction)
end

#rolesActiveRecord::Relation<Role>

Returns:

  • (ActiveRecord::Relation<Role>)

See Also:



66
# File 'app/models/topic.rb', line 66

has_and_belongs_to_many :roles

#surveySurvey

Returns:

See Also:



57
# File 'app/models/topic.rb', line 57

belongs_to :survey, inverse_of: :topics, optional: true

#tagsObject



185
186
187
188
189
190
191
192
# File 'app/models/topic.rb', line 185

def tags
  t = []
  t << 'company-profiling' if applies_to_company
  t << 'contact-profiling' if applies_to_contact
  t << 'employee-training' if applies_to_employee
  t << 'contact-training' if training_module
  t
end

#to_sObject



181
182
183
# File 'app/models/topic.rb', line 181

def to_s
  title
end

#topic_categoryTopicCategory



55
# File 'app/models/topic.rb', line 55

belongs_to :topic_category, inverse_of: :topics, optional: true

#topic_category_nameObject



194
195
196
# File 'app/models/topic.rb', line 194

def topic_category_name
  topic_category.try(:name)
end

#topic_examTopicExam

Returns:

See Also:



56
# File 'app/models/topic.rb', line 56

belongs_to :topic_exam, inverse_of: :topics, optional: true

#topic_responsesActiveRecord::Relation<TopicResponse>

Returns:

See Also:



58
# File 'app/models/topic.rb', line 58

has_many :topic_responses, -> { order(:position) }, autosave: true, inverse_of: :topic

#topic_thumbnailObject



161
162
163
# File 'app/models/topic.rb', line 161

def topic_thumbnail
  uploads.first.try(:thumbnail_url)
end

#uploadsActiveRecord::Relation<Upload>

Returns:

  • (ActiveRecord::Relation<Upload>)

See Also:



68
# File 'app/models/topic.rb', line 68

has_many :uploads, through: :articles

#valid_for_customer?(customer) ⇒ Boolean

Returns:

  • (Boolean)


223
224
225
# File 'app/models/topic.rb', line 223

def valid_for_customer?(customer)
  customer_filter.applies_to_customer? customer
end