code-mancers/rapidfire

View on GitHub
app/services/rapidfire/attempt_builder.rb

Summary

Maintainability
A
1 hr
Test Coverage
module Rapidfire
  class AttemptBuilder < Rapidfire::BaseService
    attr_accessor :user, :survey, :questions, :answers, :params, :attempt_id

    def initialize(params = {})
      super(params)
      build_attempt(params[:attempt_id])
    end

    def to_model
      @attempt
    end

    def save!(options = {})
      params.each do |question_id, answer_attributes|
        answer = @attempt.answers.find { |a| a.question_id.to_s == question_id.to_s }
        next unless answer

        text = answer_attributes[:answer_text]

        # in case of checkboxes, values are submitted as an array of
        # strings. we will store answers as one big string separated
        # by delimiter.
        text = text.values if text.is_a?(ActionController::Parameters)
        answer.answer_text =
          if text.is_a?(Array)
            strip_checkbox_answers(text).join(Rapidfire.answers_delimiter)
          else
            text
          end

        case answer.question
        when Rapidfire::Questions::MultiFile
          answer.files = answer_attributes[:files]
        when Rapidfire::Questions::File
          answer.file = answer_attributes[:file]
        end
      end

      if Rails::VERSION::MAJOR >= 5
        @attempt.save!
      else
        @attempt.save!(options)
      end
    end

    def save(options = {})
      save!(options)
    rescue ActiveRecord::ActiveRecordError => e
      errors.add(:base, e.message)
      # repopulate answers here in case of failure as they are not getting updated
      @answers = @survey.questions.collect do |question|
        @attempt.answers.find { |a| a.question_id == question.id }
      end
      false
    end

    private

    def build_attempt(attempt_id)
      if attempt_id.present?
        @attempt = Attempt.find(attempt_id)
        self.answers = @attempt.answers
        self.user = @attempt.user
        self.survey = @attempt.survey
        self.questions = @survey.questions
      else
        @attempt = Attempt.new(user: user, survey: survey)
        @answers = @survey.questions.collect do |question|
          @attempt.answers.build(question_id: question.id)
        end
      end
    end

    def strip_checkbox_answers(answers)
      answers.reject(&:blank?).reject { |t| t == "0" }
    end
  end
end