module JSONAPI class OperationsProcessor include Callbacks define_jsonapi_resources_callbacks :operation, :operations, :find_operation, :show_operation, :show_association_operation, :show_related_resource_operation, :show_related_resources_operation, :create_resource_operation, :remove_resource_operation, :replace_fields_operation, :replace_has_one_association_operation, :replace_polymorphic_has_one_association_operation, :create_has_many_association_operation, :replace_has_many_association_operation, :remove_has_many_association_operation, :remove_has_one_association_operation class << self def operations_processor_for(operations_processor) operations_processor_class_name = "#{operations_processor.to_s.camelize}OperationsProcessor" operations_processor_class_name.safe_constantize end end def process(request) @results = JSONAPI::OperationResults.new @request = request @operations = request.operations # Use transactions if more than one operation and if one of the operations can be transactional # Even if transactional transactions won't be used unless the derived OperationsProcessor supports them. @transactional = false if @operations.length > 1 @operations.each do |operation| @transactional |= operation.transactional end end run_callbacks :operations do transaction do # Links and meta data global to the set of operations @operations_meta = {} @operations_links = {} @operations.each do |operation| @operation = operation # Links and meta data for each operation @operation_meta = {} @operation_links = {} run_callbacks :operation do @result = nil run_callbacks @operation.class.name.demodulize.underscore.to_sym do @result = process_operation(@operation) end @result.meta.merge!(@operation_meta) @result.links.merge!(@operation_links) @results.add_result(@result) rollback if @results.has_errors? end end @results.meta = @operations_meta @results.links = @operations_links end end @results end private # The base OperationsProcessor provides no transaction support # Override the transaction and rollback methods to provide transaction support. # For ActiveRecord transactions you can use the ActiveRecordOperationsProcessor def transaction yield end def rollback end def process_operation(operation) operation.apply rescue JSONAPI::Exceptions::Error => e # :nocov: raise e # :nocov: rescue => e # :nocov: internal_server_error = JSONAPI::Exceptions::InternalServerError.new(e) Rails.logger.error { "Internal Server Error: #{e.message} #{e.backtrace.join("\n")}" } return JSONAPI::ErrorsOperationResult.new(internal_server_error.errors[0].code, internal_server_error.errors) # :nocov: end end end class BasicOperationsProcessor < JSONAPI::OperationsProcessor end