module JSONAPI::Utils::Response::Formatters
Public Instance Methods
Helper method to format ActiveRecord or Hash objects into JSON API-compliant ones.
@note The return of this method represents what will actually be displayed in the response body. @note It can also be called as jsonapi_serialize
due to backward compatibility issues.
@param object [ActiveRecord::Base, ActiveRecord::Relation, Hash, Array<Hash>]
Object to be formatted into JSON e.g.: User.first, User.all, { data: { id: 1, first_name: 'Tiago' } }, [{ data: { id: 1, first_name: 'Tiago' } }]
@option options [JSONAPI::Resource] resource: it tells the formatter which resource
class to be used rather than use an infered one (default behaviour)
@option options [JSONAPI::Resource] source: it tells the formatter that this response is from a related resource
and the result should be interpreted as a related resources response
@option options [String, Symbol] relationship_type: it tells that the formatter which relationship the data is from
@option options [ActiveRecord::Base] model: ActiveRecord model class to be instantiated
when a Hash or Array of Hashes is passed as the "object" argument
@option options [Integer] count: if it's rendering a collection of resources, the default
gem's counting method can be bypassed by the use of this options. It's shows then the total records resulting from that request and also calculates the pagination.
@return [Hash]
@api public
# File lib/jsonapi/utils/response/formatters.rb, line 33 def jsonapi_format(object, options = {}) if object.is_a?(Hash) hash = object.with_indifferent_access object = hash_to_active_record(hash[:data], options[:model]) end fix_custom_request_options(object) build_response_document(object, options).contents end
Helper method to format ActiveRecord or any object that responds to errors into JSON API-compliant error response bodies.
@note The return of this method represents what will actually be displayed in the response body. @note It can also be called as jsonapi_serialize_errors
due to backward compatibility issues.
@param object [ActiveRecord::Base or any object that responds to errors]
Error object to be serialized into JSON e.g.: User.new(name: nil).tap(&:save), MyErrorDecorator.new(invalid_object)
@return [Array]
@api public
# File lib/jsonapi/utils/response/formatters.rb, line 57 def jsonapi_format_errors(object) if active_record_obj?(object) object = JSONAPI::Utils::Exceptions::ActiveRecord.new(object, @request.resource_klass, context) end errors = object.respond_to?(:errors) ? object.errors : object JSONAPI::Utils::Support::Error.sanitize(errors).uniq end
Private Instance Methods
Check whether the given object is an ActiveRecord-like one.
@param object [Object] Object to be checked
@return [TrueClass, FalseClass]
@api private
# File lib/jsonapi/utils/response/formatters.rb, line 76 def active_record_obj?(object) defined?(ActiveRecord::Base) && (object.is_a?(ActiveRecord::Base) || object.singleton_class.include?(ActiveModel::Model)) end
Turn a collection of AR or Hash objects into a collection of JSONAPI::Resource ones.
@param records [ActiveRecord::Relation, Hash, Array<Hash>]
Objects to be instantiated as JSONAPI::Resource ones. e.g.: User.all, [{ data: { id: 1, first_name: 'Tiago' } }]
@option options [JSONAPI::Resource] :resource it resource class to be used rather than default one (infered)
@option options [Integer] :count if it's rendering a collection of resources, the default
gem's counting method can be bypassed by the use of this options. It's shows then the total records resulting from that request and also calculates the pagination.
@return [Array]
@api private
# File lib/jsonapi/utils/response/formatters.rb, line 215 def build_collection(records, options) records = apply_filter(records, options) records = apply_sort(records) records = apply_pagination(records, options) records.respond_to?(:to_ary) ? records.map { |record| turn_into_resource(record, options) } : [] end
Build the result operation object for collection actions.
@param object [ActiveRecord::Relation, Array<Hash>]
Object to be formatted into JSON.
@option options [JSONAPI::Resource] :resource which resource class to be used
rather than using the default one (inferred)
@option options [ActiveRecord::Base, JSONAPI::Resource] :source parent model/resource
of the related resource
@option options [String, Symbol] :relationship which relationship the data is from
@option options [Integer] count: if it's rendering a collection of resources, the default
gem's counting method can be bypassed by the use of this options. It's shows then the total records resulting from that request and also calculates the pagination.
@return [JSONAPI::ResourcesOperationResult, JSONAPI::RelatedResourcesOperationResult]
@api private
# File lib/jsonapi/utils/response/formatters.rb, line 135 def build_collection_result(object, options) records = build_collection(object, options) result_options = result_options(object, options) if related_resource_operation?(options) source_resource = turn_source_into_resource(options[:source]) relationship_type = get_source_relationship(options) JSONAPI::RelatedResourcesOperationResult.new( :ok, source_resource, relationship_type, records, result_options ) else JSONAPI::ResourcesOperationResult.new(:ok, records, result_options) end end
Build the full response document.
@param object [ActiveRecord::Base, ActiveRecord::Relation, Hash, Array<Hash>]
Object to be formatted into JSON.
@option options [JSONAPI::Resource] :resource which resource class to be used
rather than using the default one (inferred)
@option options [ActiveRecord::Base, JSONAPI::Resource] :source source of related resource,
the result should be interpreted as a related resources response
@option options [String, Symbol] :relationship which relationship the data is from
@option options [Integer] count: if it's rendering a collection of resources, the default
gem's counting method can be bypassed by the use of this options. It's shows then the total records resulting from that request and also calculates the pagination.
@return [JSONAPI::ResponseDocument]
@api private
# File lib/jsonapi/utils/response/formatters.rb, line 102 def build_response_document(object, options) results = JSONAPI::OperationResults.new if object.respond_to?(:to_ary) results.add_result(build_collection_result(object, options)) else record = turn_into_resource(object, options) results.add_result(JSONAPI::ResourceOperationResult.new(:ok, record)) end @_response_document = create_response_document(results) end
Check whether it's a custom GET request with params.
@return [TrueClass, FalseClass]
@api private
# File lib/jsonapi/utils/response/formatters.rb, line 196 def custom_get_request_with_params? request.method =~ /get/i && !%w(index show).include?(params[:action]) && !params.nil? end
Apply a proper action setup for custom requests/actions.
@note The setup_(index|show)_action comes from JSONAPI::Resources' API.
@param object [ActiveRecord::Base, ActiveRecord::Relation, Hash, Array<Hash>]
It's checked whether this object refers to a collection or not.
@api private
# File lib/jsonapi/utils/response/formatters.rb, line 185 def fix_custom_request_options(object) return unless custom_get_request_with_params? action = object.respond_to?(:to_ary) ? 'index' : 'show' @request.send("setup_#{action}_action", params) end
Get relationship type of source object
@option options [Symbol] relationship: it tells which relationship
to be used rather than use an infered one (default behaviour)
@return [Symbol]
@api private
# File lib/jsonapi/utils/response/formatters.rb, line 262 def get_source_relationship(options) options[:relationship]&.to_sym || @request.resource_klass._type end
Convert Hash or collection of Hashes into AR objects.
@param data [Hash, Array<Hash>] Hash or collection to be converted
e.g.: { data: { id: 1, first_name: 'Tiago' } }, [{ data: { id: 1, first_name: 'Tiago' } }],
@option options [ActiveRecord::Base] model: ActiveRecord model class to be
used as base for the objects' intantialization.
@return [ActiveRecord::Base, ActiveRecord::Relation]
@api private
# File lib/jsonapi/utils/response/formatters.rb, line 307 def hash_to_active_record(data, model) return data if model.nil? coerced = [data].flatten.map { |hash| model.new(hash) } data.is_a?(Array) ? coerced : coerced.first rescue ActiveRecord::UnknownAttributeError if data.is_a?(Array) ids = data.map { |e| e[:id] } model.where(id: ids) else model.find_by(id: data[:id]) end end
Apply some result options like pagination params and record count to collection responses.
@param records [ActiveRecord::Relation, Hash, Array<Hash>]
Object to be formatted into JSON e.g.: User.all, [{ data: { id: 1, first_name: 'Tiago' } }]
@option options [Integer] count: if it's rendering a collection of resources, the default
gem's counting method can be bypassed by the use of this options. It's shows then the total records resulting from that request and also calculates the pagination.
@return [Hash]
@api private
# File lib/jsonapi/utils/response/formatters.rb, line 279 def result_options(records, options) {}.tap do |data| if include_pagination_links? data[:pagination_params] = pagination_params(records, options) end if JSONAPI.configuration.top_level_meta_include_record_count data[:record_count] = record_count_for(records, options) end if include_page_count? data[:page_count] = page_count_for(data[:record_count]) end end end
Turn an AR or Hash object into a JSONAPI::Resource one.
@param records [ActiveRecord::Relation, Hash, Array<Hash>]
Object to be instantiated as a JSONAPI::Resource one. e.g.: User.first, { data: { id: 1, first_name: 'Tiago' } }
@option options [JSONAPI::Resource] resource: it tells which resource
class to be used rather than use an infered one (default behaviour)
@return [JSONAPI::Resource]
@api private
# File lib/jsonapi/utils/response/formatters.rb, line 234 def turn_into_resource(record, options) if options[:resource] options[:resource].to_s.constantize.new(record, context) else @request.resource_klass.new(record, context) end end
Get JSONAPI::Resource for source object
@param record [ActiveRecord::Base, JSONAPI::Resource]
@return [JSONAPI::Resource]
@api private
# File lib/jsonapi/utils/response/formatters.rb, line 249 def turn_source_into_resource(record) return record if record.kind_of?(JSONAPI::Resource) @request.source_klass.new(record, context) end