dr-click/questionnaire

View on GitHub
app/models/survey/attempt.rb

Summary

Maintainability
A
0 mins
Test Coverage
class Survey::Attempt < ActiveRecord::Base

  self.table_name = "survey_attempts"

  # relations

  has_many :answers
  belongs_to :survey
  belongs_to :participant, :polymorphic => true

  #rails 3 attr_accessible support
  if Rails::VERSION::MAJOR < 4
    attr_accessible :participant_id, :survey_id, :answers_attributes, :survey, :winner, :participant
  end
  
  # validations
  validates :participant_id, :participant_type,
    :presence => true
    
  accepts_nested_attributes_for :answers,
    :reject_if =>
      ->(q) { q[:question_id].blank? && q[:option_id].blank? }, 
      allow_destroy: true

  #scopes

  scope :for_survey, ->(survey) {
  where(:survey_id => survey.try(:id))
  }

  scope :exclude_survey, ->(survey) {
  where("NOT survey_id = #{survey.try(:id)}")
  }

  scope :for_participant, ->(participant) {
  where(:participant_id => participant.try(:id),
    :participant_type => participant.class)
  }

  scope :wins, -> { where(:winner => true) }
  scope :looses, -> { where(:winner => false) }
  scope :scores, -> { order("score DESC") }

  # callbacks

  validate :check_number_of_attempts_by_survey, :on => :create
  before_create :collect_scores

  def correct_answers
    self.answers.where(:correct => true)
  end

  def incorrect_answers
    self.answers.where(:correct => false)
  end

  def self.high_score
    scores.first.score
  end

  private

  def check_number_of_attempts_by_survey
    attempts = self.class.for_survey(survey).for_participant(participant)
    upper_bound = self.survey.attempts_number
    if attempts.size >= upper_bound and upper_bound != 0
      errors.add(:questionnaire_id, "Number of attempts exceeded")
    end
  end

  def collect_scores
    self.score = self.answers.map(&:value).reduce(:+)
  end
end