sanger/limber

View on GitHub
app/controllers/creation_controller.rb

Summary

Maintainability
A
0 mins
Test Coverage
C
71%
# frozen_string_literal: true

# Base class for labware creation. Inherited by PlateCreationController and TubeCreationController.
# Controllers find the appropriate LabwareCreator specified by the purpose configuration
# new => renders the form specified by the labware creator,
#        This usually indicates that further information needs to be supplied by the user,
#        or that we need to display an interstitial page
# create => Use the specified labware creator to generate the resource. Will usually redirect
#           to the asset that has just been created, but may redirect to the parent if there are multiple children.
class CreationController < ApplicationController
  before_action :check_for_current_user!
  rescue_from Sequencescape::Api::ResourceInvalid, LabwareCreators::ResourceInvalid, with: :creation_failed
  rescue_from Sequencescape::Api::ConnectionFactory::Actions::ServerError, with: :sequencescape_api_server_error

  def new
    params[:parent_uuid] ||= parent_uuid
    @labware_creator = labware_creator(params.permit(permitted_attributes))
    respond_to { |format| format.html { render(@labware_creator.page) } }
  end

  def create
    creator_params[:parent_uuid] ||= parent_uuid
    @labware_creator = labware_creator(creator_params)
    @labware_creator.save ? create_success : create_failure
  end

  def labware_creator(form_attributes)
    creator_class.new(api, form_attributes.permit(permitted_attributes).merge(params_for_creator_build))
  end

  def creation_failed(exception)
    Rails.logger.error("Cannot create child of #{@labware_creator.parent.uuid}")
    Rails.logger.error(exception.message)
    exception.backtrace.map(&Rails.logger.method(:error)) # rubocop:todo Performance/MethodObjectAsBlock

    redirect_back_after_error('Cannot create the next piece of labware:', exception.resource.errors.full_messages)
  end

  def sequencescape_api_server_error(exception)
    Rails.logger.error("Cannot create child of #{@labware_creator.parent.uuid}, Sequencescape api server error(s)")
    Rails.logger.error(exception.message)
    exception.backtrace.map(&Rails.logger.method(:error)) # rubocop:todo Performance/MethodObjectAsBlock

    api_error_messages = extract_error_messages_from_api_exception(exception.message)

    redirect_back_after_error(
      'Cannot create the next piece of labware, Sequencescape server API error(s):',
      api_error_messages
    )
  end

  private

  def create_success
    respond_to do |format|
      format.json do
        render json: { redirect: redirection_path(@labware_creator), message: 'Plate created, redirecting...' }
      end
      format.html do
        redirect_to redirection_path(@labware_creator), notice: 'New empty labware added to the system.' # rubocop:todo Rails/I18nLocaleTexts
      end
    end
  end

  def create_failure # rubocop:todo Metrics/AbcSize
    Rails.logger.error(@labware_creator.errors.full_messages)
    respond_to do |format|
      format.json { render json: { message: @labware_creator.errors.full_messages }, status: :bad_request }
      format.html do
        flash.now.alert = @labware_creator.errors.full_messages
        render @labware_creator.page
      end
    end
  end

  def permitted_attributes
    creator_class.attributes
  end

  def creator_class
    @creator_class ||= LabwareCreators.class_for(params_purpose_uuid)
  end

  def params_for_creator_build
    LabwareCreators.params_for(params_purpose_uuid).merge({ user_uuid: current_user_uuid })
  end

  def params_purpose_uuid
    params[:purpose_uuid] || creator_params.fetch(:purpose_uuid)
  end

  def parent_uuid
    params[:limber_tube_id] || params[:limber_plate_id]
  end

  def extract_error_messages_from_api_exception(api_message)
    api_errors_hash = JSON.parse(api_message) || {}
    api_errors_hash.key?('general') ? api_errors_hash['general'] : [api_message]
  end

  def redirect_back_after_error(prefix_message, error_messages)
    flash_messages = [prefix_message] + Array(error_messages)
    respond_to do |format|
      format.html do
        redirect_back(fallback_location: url_for(@labware_creator.parent), alert: truncate_flash(flash_messages))
      end
    end
  end
end