Newer
Older
dmpopidor / app / controllers / org_admin / questions_controller.rb
@briley briley on 23 May 2018 6 KB Template Versioning
module OrgAdmin
  class QuestionsController < ApplicationController
    include Versionable
  
    respond_to :html
    after_action :verify_authorized

    # GET /org_admin/templates/[:template_id]/phases/[:phase_id]/sections/[:section_id]/question/[:id]
    def show
      question = Question.includes(:annotations, :question_options, section: { phase: :template }).find(params[:id])
      authorize question
      render partial: 'show', locals: { 
        template: question.section.phase.template, 
        section: question.section,
        question: question 
      }
    end
    
    # GET /org_admin/templates/[:template_id]/phases/[:phase_id]/sections/[:section_id]/question/[:id]/edit
    def edit
      question = Question.includes(:annotations, :question_options, section: { phase: :template }).find(params[:id])
      authorize question
      render partial: 'edit', locals: { 
        template: question.section.phase.template, 
        section: question.section,
        question: question 
      }
    end
    
    # GET /org_admin/templates/[:template_id]/phases/[:phase_id]/sections/[:section_id]/questions/new
    def new
      section = Section.includes(:questions, phase: :template).find(params[:section_id])
      nbr = section.questions.maximum(:number)
      question = Question.new({ section_id: section.id, question_format: QuestionFormat.find_by(title: 'Text area'), number: nbr.present? ? nbr + 1 : 1 })
      authorize question
      render partial: 'form', locals: { 
        template: section.phase.template, 
        section: section,
        question: question,
        method: 'post',
        url: org_admin_template_phase_section_questions_path(template_id: section.phase.template.id, phase_id: section.phase.id, id: section.id)
      }
    end

    # POST /org_admin/templates/[:template_id]/phases/[:phase_id]/sections/[:section_id]/questions
    def create
      question = Question.new(question_params.merge({ section_id: params[:section_id] }))
      authorize question
      begin
        question = get_new(question)
        section = question.section
        if question.save!
          flash[:notice] = success_message(_('question'), _('created'))
        else
          flash[:alert] = failed_create_error(question, _('question'))
        end
      rescue StandardError => e
        flash[:alert] = _('Unable to create a new version of this template.')
      end
      redirect_to edit_org_admin_template_phase_path(template_id: section.phase.template.id, id: section.phase.id, section: section.id)
    end

    # PUT /org_admin/templates/[:template_id]/phases/[:phase_id]/sections/[:section_id]/questions/[:id]
    def update
      question = Question.find(params[:id])
      authorize question
      begin
        question = get_modifiable(question)
        # Need to reattach the incoming annotation's and question_options to the 
        # modifiable (versioned) question
        attrs = question_params
        attrs = transfer_associations(question) if question.id != params[:id]
        if question.update!(attrs)
          flash[:notice] = success_message(_('question'), _('updated'))
        else
          flash[:alert] = failed_update_error(question, _('question'))
        end
      rescue StandardError => e
        puts e.message
        flash[:alert] = _('Unable to create a new version of this template.')
      end
      if question.section.phase.template.customization_of.present?
        redirect_to org_admin_template_phase_path({
          template_id: question.section.phase.template.id, 
          id: question.section.phase.id, 
          section: question.section.id
        })
      else
        redirect_to edit_org_admin_template_phase_path({
          template_id: question.section.phase.template.id, 
          id: question.section.phase.id, 
          section: question.section.id
        })
      end
    end

    # DELETE /org_admin/templates/[:template_id]/phases/[:phase_id]/sections/[:section_id]/questions/[:id]
    def destroy
      question = Question.find(params[:id])
      authorize question
      begin
        question = get_modifiable(question)
        section = question.section
        if question.destroy!
          flash[:notice] = success_message(_('question'), _('deleted'))
        else
          flash[:alert] = failed_destroy_error(question, 'question')
        end
      rescue StandardError => e
        flash[:alert] = _('Unable to create a new version of this template.')
      end
      redirect_to edit_org_admin_template_phase_path({
        template_id: section.phase.template.id, 
        id: section.phase.id, 
        section: section.id
      })
    end

    private
      def question_params
        params.require(:question).permit(:number, :text, :question_format_id, :option_comment_display, :default_value, question_options_attributes: [:id, :number, :text, :is_default, :_destroy], annotations_attributes: [:id, :text, :org_id, :org, :type], theme_ids: [])
      end
      
      # When a template gets versioned by changes to one of its questions we need to loop 
      # through the incoming params and ensure that the annotations and question_options
      # get attached to the new question
      def transfer_associations(question)
        attrs = question_params
        if attrs[:annotations_attributes].present?
          attrs[:annotations_attributes].each_key do |key|
            old_annotation = question.annotations.select do |a| 
              a.org_id.to_s == attrs[:annotations_attributes][key][:org_id] && a.type.to_s == attrs[:annotations_attributes][key][:type] 
            end
            attrs[:annotations_attributes][key][:id] = old_annotation.first.id unless old_annotation.empty?
          end
        end
        # TODO: This question_options id swap feel fragile. We cannot really match on any of the
        #       data elements because the user may have changed them so we rely on its position
        #       within the array/query since they should be equivalent. 
        if attrs[:question_options_attributes].present?
          attrs[:question_options_attributes].each_key do |key|
            attrs[:question_options_attributes][key][:id] = question.question_options[key.to_i].id.to_s if question.question_options[key.to_i].present?
          end
        end
        attrs
      end
  end
end