lib/question.rb
module Question
end
module Question::Model
extend ActiveSupport::Concern
included do
belongs_to :instrument
belongs_to :instruction
has_many :rds_qs, class_name: 'RdsQs', as: :question, dependent: :destroy
has_many :response_domain_codes, through: :rds_qs, source: :response_domain, source_type: 'ResponseDomainCode'
has_many :response_domain_datetimes, through: :rds_qs, source: :response_domain, source_type: 'ResponseDomainDatetime'
has_many :response_domain_numerics, through: :rds_qs, source: :response_domain, source_type: 'ResponseDomainNumeric'
has_many :response_domain_texts, through: :rds_qs, source: :response_domain, source_type: 'ResponseDomainText'
has_many :cc_questions, as: :question, dependent: :destroy, inverse_of: :question
validates :instrument, presence: true
validates :label, uniqueness: {scope: [:instrument_id, :question_type]}
validates :literal, presence: true
include Exportable
# This model can be tracked using an Identifier
include Identifiable
NS ||= 'd'
before_create :no_duplicates
#validates :label, uniqueness: { scope: :instrument_id }
alias constructs cc_questions
def instruction=(text)
if text.to_s == ''
association(:instruction).writer nil
elsif association(:instruction).reader.nil? || association(:instruction).reader.text != text
association(:instruction).writer Instruction.find_or_create_by(text: text, instrument: self.instrument)
end
end
def update_cols(cols)
if cols.to_a.empty?
self.rds_qs.delete_all
else
cols.sort_by! { |x| x[:order] }
cols.each do |col|
existing_rd = self.rds_qs.where(code_id: col[:value]).first
# Get the ResponseDomain from the col hash. If the type and id aren't
# found in the db or if we're removing an assoication then this
# will rescue to nil.
new_rd = self.instrument.association(col[:rd][:type].tableize).reader.find(col[:rd][:id]) rescue nil
if existing_rd && new_rd != existing_rd
existing_rd.delete
end
if new_rd
self.rds_qs.create question: self, response_domain: new_rd, code_id: col[:value], instrument_id: self.instrument.try(:id)
end
end
end
end
def update_rds(rds)
if rds.nil?
self.response_domain_codes =
self.response_domain_datetimes =
self.response_domain_numerics =
self.response_domain_texts = []
else
rds.each_index { |i| rds[i][:rd_order] = i + 1 }
self.transaction do
self.response_domains.each do |rd|
index = rds.index { |x| x[:id] == rd[:id] && x[:type] == rd.class.name }
if index.nil?
#ResponseDomain is no longer included
rd.rds_qs.where(question_type: self.class.name, question_id: self.id).each {|x| x.destroy;}
else
joint = rd.rds_qs.where(question_type: self.class.name, question_id: self.id).first
joint.rd_order = rds[index][:rd_order]
joint.save!
end
end
end
self.reload
if self.response_domains.length < rds.length
add_rds rds
end
end
self.reload
end
def add_rds(rds)
# If there are no rds_qs associations, set the highest_rd_order to 0, otherwise get the highest rd_order value.
if self.rds_qs.length < 1
highest_rd_order = 0
else
highest_rd_order = self.rds_qs.order(:rd_order).last.rd_order
end
# Map the input rds array to an array of hashes containing the actual response domain objects and their rd_order.
o_rds = rds.map { |x| { rd: x[:type].constantize.find(x[:id]), rd_order: x[:rd_order] } }
# Filter out the response domains that are already associated with the question.
new_rds = o_rds.reject { |x| self.response_domains.include? x[:rd] }
# Iterate through the new_rds array, increment the highest_rd_order, and create a new RdsQs instance.
new_rds.each_with_index do |new_rd, index|
highest_rd_order += 1
RdsQs.create instrument_id: self.instrument.try(:id),
response_domain: new_rd[:rd],
question: self,
rd_order: new_rd.fetch(:rd_order, highest_rd_order)
end
end
private
def no_duplicates
until self.instrument.send(self.class.name.tableize.to_sym).find_by_label(self.label).nil?
self.label += '_dup'
end
end
end
end