diff --git a/Gemfile b/Gemfile index 1bba46ea9..bfb0386fb 100644 --- a/Gemfile +++ b/Gemfile @@ -13,9 +13,9 @@ end version = ENV['RAILS_VERSION'] || 'default' rails = case version when 'master' - {:github => 'rails/rails'} + { github: 'rails/rails' } when 'default' - '>= 4.2' + '>= 4.2' else "~> #{version}" end diff --git a/Rakefile b/Rakefile index 27520d7d6..70623f586 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,6 @@ #!/usr/bin/env rake -require "bundler/gem_tasks" -require "rake/testtask" +require 'bundler/gem_tasks' +require 'rake/testtask' require './test/test_helper.rb' TestApp.load_tasks diff --git a/jsonapi-resources.gemspec b/jsonapi-resources.gemspec index ca68ca234..7bc6a8f5d 100644 --- a/jsonapi-resources.gemspec +++ b/jsonapi-resources.gemspec @@ -8,8 +8,8 @@ Gem::Specification.new do |spec| spec.version = JSONAPI::Resources::VERSION spec.authors = ['Dan Gebhardt', 'Larry Gebhardt'] spec.email = ['dan@cerebris.com', 'larry@cerebris.com'] - spec.summary = %q{Easily support JSON API in Rails.} - spec.description = %q{A resource-centric approach to implementing the controllers, routes, and serializers needed to support the JSON API spec.} + spec.summary = 'Easily support JSON API in Rails.' + spec.description = 'A resource-centric approach to implementing the controllers, routes, and serializers needed to support the JSON API spec.' spec.homepage = 'https://github.com/cerebris/jsonapi-resources' spec.license = 'MIT' diff --git a/lib/jsonapi-resources.rb b/lib/jsonapi-resources.rb index 899e54a1d..36f47c7ac 100644 --- a/lib/jsonapi-resources.rb +++ b/lib/jsonapi-resources.rb @@ -20,4 +20,3 @@ require 'jsonapi/operation_result' require 'jsonapi/operation_results' require 'jsonapi/callbacks' - diff --git a/lib/jsonapi/active_record_operations_processor.rb b/lib/jsonapi/active_record_operations_processor.rb index 0af51eb2b..c8a1849f2 100644 --- a/lib/jsonapi/active_record_operations_processor.rb +++ b/lib/jsonapi/active_record_operations_processor.rb @@ -1,6 +1,6 @@ class ActiveRecordOperationsProcessor < JSONAPI::OperationsProcessor - private + def transaction if @transactional ActiveRecord::Base.transaction do @@ -12,7 +12,7 @@ def transaction end def rollback - raise ActiveRecord::Rollback if @transactional + fail ActiveRecord::Rollback if @transactional end def process_operation(operation) diff --git a/lib/jsonapi/acts_as_resource_controller.rb b/lib/jsonapi/acts_as_resource_controller.rb index 2a139d3fe..8f49476e7 100644 --- a/lib/jsonapi/acts_as_resource_controller.rb +++ b/lib/jsonapi/acts_as_resource_controller.rb @@ -60,6 +60,7 @@ def create_operations_processor end private + def resource_klass @resource_klass ||= resource_klass_name.safe_constantize end @@ -78,17 +79,15 @@ def resource_klass_name def ensure_correct_media_type unless request.content_type == JSONAPI::MEDIA_TYPE - raise JSONAPI::Exceptions::UnsupportedMediaTypeError.new(request.content_type) + fail JSONAPI::Exceptions::UnsupportedMediaTypeError.new(request.content_type) end rescue => e handle_exceptions(e) end def setup_request - @request = JSONAPI::Request.new(params, { - context: context, - key_formatter: key_formatter - }) + @request = JSONAPI::Request.new(params, context: context, + key_formatter: key_formatter) render_errors(@request.errors) unless @request.errors.empty? rescue => e handle_exceptions(e) @@ -128,7 +127,7 @@ def base_response_links end def render_errors(errors) - operation_results = JSONAPI::OperationResults.new() + operation_results = JSONAPI::OperationResults.new result = JSONAPI::ErrorsOperationResult.new(errors[0].status, errors) operation_results.add_result(result) @@ -143,18 +142,16 @@ def render_results(operation_results) def create_response_document(operation_results) JSONAPI::ResponseDocument.new( operation_results, - { - primary_resource_klass: resource_klass, - include_directives: @request ? @request.include_directives : nil, - fields: @request ? @request.fields : nil, - base_url: base_url, - key_formatter: key_formatter, - route_formatter: route_formatter, - base_meta: base_response_meta, - base_links: base_response_links, - resource_serializer_klass: resource_serializer_klass, - request: @request - } + primary_resource_klass: resource_klass, + include_directives: @request ? @request.include_directives : nil, + fields: @request ? @request.fields : nil, + base_url: base_url, + key_formatter: key_formatter, + route_formatter: route_formatter, + base_meta: base_response_meta, + base_links: base_response_links, + resource_serializer_klass: resource_serializer_klass, + request: @request ) end @@ -169,11 +166,11 @@ def process_request_operations # Note: Be sure to either call super(e) or handle JSONAPI::Exceptions::Error and raise unhandled exceptions def handle_exceptions(e) case e - when JSONAPI::Exceptions::Error - render_errors(e.errors) - else # raise all other exceptions - # :nocov: - raise e + when JSONAPI::Exceptions::Error + render_errors(e.errors) + else # raise all other exceptions + # :nocov: + fail e # :nocov: end end diff --git a/lib/jsonapi/association.rb b/lib/jsonapi/association.rb index 01d6e0446..e195686e7 100644 --- a/lib/jsonapi/association.rb +++ b/lib/jsonapi/association.rb @@ -2,11 +2,11 @@ module JSONAPI class Association attr_reader :acts_as_set, :foreign_key, :type, :options, :name, :class_name - def initialize(name, options={}) + def initialize(name, options = {}) @name = name.to_s @options = options @acts_as_set = options.fetch(:acts_as_set, false) == true - @foreign_key = options[:foreign_key ] ? options[:foreign_key ].to_sym : nil + @foreign_key = options[:foreign_key] ? options[:foreign_key].to_sym : nil @module_path = options[:module_path] || '' end @@ -15,7 +15,7 @@ def primary_key end class HasOne < Association - def initialize(name, options={}) + def initialize(name, options = {}) super @class_name = options.fetch(:class_name, name.to_s.capitalize) @type = class_name.underscore.pluralize.to_sym @@ -24,11 +24,11 @@ def initialize(name, options={}) end class HasMany < Association - def initialize(name, options={}) + def initialize(name, options = {}) super @class_name = options.fetch(:class_name, name.to_s.capitalize.singularize) @type = class_name.underscore.pluralize.to_sym - @foreign_key ||= "#{name.to_s.singularize}_ids".to_sym + @foreign_key ||= "#{name.to_s.singularize}_ids".to_sym end end end diff --git a/lib/jsonapi/callbacks.rb b/lib/jsonapi/callbacks.rb index 16763f0ef..474f50f48 100644 --- a/lib/jsonapi/callbacks.rb +++ b/lib/jsonapi/callbacks.rb @@ -2,7 +2,6 @@ module JSONAPI module Callbacks - def self.included(base) base.class_eval do include ActiveSupport::Callbacks @@ -49,4 +48,4 @@ def _define_after_callback(klass, callback) #:nodoc: end end end -end \ No newline at end of file +end diff --git a/lib/jsonapi/configuration.rb b/lib/jsonapi/configuration.rb index 6e677cf69..31af8f497 100644 --- a/lib/jsonapi/configuration.rb +++ b/lib/jsonapi/configuration.rb @@ -62,37 +62,21 @@ def operations_processor=(operations_processor) @operations_processor = JSONAPI::OperationsProcessor.operations_processor_for(@operations_processor_name) end - def allowed_request_params=(allowed_request_params) - @allowed_request_params = allowed_request_params - end + attr_writer :allowed_request_params - def default_paginator=(default_paginator) - @default_paginator = default_paginator - end + attr_writer :default_paginator - def default_page_size=(default_page_size) - @default_page_size = default_page_size - end + attr_writer :default_page_size - def maximum_page_size=(maximum_page_size) - @maximum_page_size = maximum_page_size - end + attr_writer :maximum_page_size - def use_text_errors=(use_text_errors) - @use_text_errors = use_text_errors - end + attr_writer :use_text_errors - def top_level_links_include_pagination=(top_level_links_include_pagination) - @top_level_links_include_pagination = top_level_links_include_pagination - end + attr_writer :top_level_links_include_pagination - def top_level_meta_include_record_count=(top_level_meta_include_record_count) - @top_level_meta_include_record_count = top_level_meta_include_record_count - end + attr_writer :top_level_meta_include_record_count - def top_level_meta_record_count_key=(top_level_meta_record_count_key) - @top_level_meta_record_count_key = top_level_meta_record_count_key - end + attr_writer :top_level_meta_record_count_key end class << self diff --git a/lib/jsonapi/error.rb b/lib/jsonapi/error.rb index cea41559c..6e86d2fc4 100644 --- a/lib/jsonapi/error.rb +++ b/lib/jsonapi/error.rb @@ -1,9 +1,8 @@ module JSONAPI class Error - attr_accessor :title, :detail, :id, :href, :code, :path, :links, :status - def initialize(options={}) + def initialize(options = {}) @title = options[:title] @detail = options[:detail] @id = options[:id] diff --git a/lib/jsonapi/exceptions.rb b/lib/jsonapi/exceptions.rb index a79cb6adc..23076b4ab 100644 --- a/lib/jsonapi/exceptions.rb +++ b/lib/jsonapi/exceptions.rb @@ -15,7 +15,6 @@ def errors title: 'Internal Server Error', detail: 'Internal Server Error')] end - end class InvalidResource < Error @@ -26,9 +25,9 @@ def initialize(resource) def errors [JSONAPI::Error.new(code: JSONAPI::INVALID_RESOURCE, - status: :bad_request, - title: 'Invalid resource', - detail: "#{resource} is not a valid resource.")] + status: :bad_request, + title: 'Invalid resource', + detail: "#{resource} is not a valid resource.")] end end @@ -40,9 +39,9 @@ def initialize(id) def errors [JSONAPI::Error.new(code: JSONAPI::RECORD_NOT_FOUND, - status: :not_found, - title: 'Record not found', - detail: "The record identified by #{id} could not be found.")] + status: :not_found, + title: 'Record not found', + detail: "The record identified by #{id} could not be found.")] end end @@ -54,9 +53,9 @@ def initialize(media_type) def errors [JSONAPI::Error.new(code: JSONAPI::UNSUPPORTED_MEDIA_TYPE, - status: :unsupported_media_type, - title: 'Unsupported media type', - detail: "All requests that create or update resources must use the '#{JSONAPI::MEDIA_TYPE}' Content-Type. This request specified '#{media_type}.'")] + status: :unsupported_media_type, + title: 'Unsupported media type', + detail: "All requests that create or update resources must use the '#{JSONAPI::MEDIA_TYPE}' Content-Type. This request specified '#{media_type}.'")] end end @@ -91,9 +90,9 @@ def initialize(filters) def errors [JSONAPI::Error.new(code: JSONAPI::INVALID_FILTERS_SYNTAX, - status: :bad_request, - title: 'Invalid filters syntax', - detail: "#{filters} is not a valid syntax for filtering.")] + status: :bad_request, + title: 'Invalid filters syntax', + detail: "#{filters} is not a valid syntax for filtering.")] end end @@ -105,9 +104,9 @@ def initialize(filter) def errors [JSONAPI::Error.new(code: JSONAPI::FILTER_NOT_ALLOWED, - status: :bad_request, - title: 'Filter not allowed', - detail: "#{filter} is not allowed.")] + status: :bad_request, + title: 'Filter not allowed', + detail: "#{filter} is not allowed.")] end end @@ -120,9 +119,9 @@ def initialize(filter, value) def errors [JSONAPI::Error.new(code: JSONAPI::INVALID_FILTER_VALUE, - status: :bad_request, - title: 'Invalid filter value', - detail: "#{value} is not a valid value for #{filter}.")] + status: :bad_request, + title: 'Invalid filter value', + detail: "#{value} is not a valid value for #{filter}.")] end end @@ -135,9 +134,9 @@ def initialize(field, value) def errors [JSONAPI::Error.new(code: JSONAPI::INVALID_FIELD_VALUE, - status: :bad_request, - title: 'Invalid field value', - detail: "#{value} is not a valid value for #{field}.")] + status: :bad_request, + title: 'Invalid field value', + detail: "#{value} is not a valid value for #{field}.")] end end @@ -182,9 +181,9 @@ def initialize(type, field) def errors [JSONAPI::Error.new(code: JSONAPI::INVALID_FIELD, - status: :bad_request, - title: 'Invalid field', - detail: "#{field} is not a valid field for #{type}.")] + status: :bad_request, + title: 'Invalid field', + detail: "#{field} is not a valid field for #{type}.")] end end @@ -225,13 +224,12 @@ def initialize(params) end def errors - params.collect { |param| - JSONAPI::Error.new(code: JSONAPI::PARAM_NOT_ALLOWED, + params.collect do |param| + JSONAPI::Error.new(code: JSONAPI::PARAM_NOT_ALLOWED, status: :bad_request, title: 'Param not allowed', detail: "#{param} is not allowed.") - } - + end end end @@ -243,18 +241,18 @@ def initialize(param) def errors [JSONAPI::Error.new(code: JSONAPI::PARAM_MISSING, - status: :bad_request, - title: 'Missing Parameter', - detail: "The required parameter, #{param}, is missing.")] + status: :bad_request, + title: 'Missing Parameter', + detail: "The required parameter, #{param}, is missing.")] end end class CountMismatch < Error def errors [JSONAPI::Error.new(code: JSONAPI::COUNT_MISMATCH, - status: :bad_request, - title: 'Count to key mismatch', - detail: 'The resource collection does not contain the same number of objects as the number of keys.')] + status: :bad_request, + title: 'Count to key mismatch', + detail: 'The resource collection does not contain the same number of objects as the number of keys.')] end end @@ -266,18 +264,18 @@ def initialize(key) def errors [JSONAPI::Error.new(code: JSONAPI::KEY_NOT_INCLUDED_IN_URL, - status: :bad_request, - title: 'Key is not included in URL', - detail: "The URL does not support the key #{key}")] + status: :bad_request, + title: 'Key is not included in URL', + detail: "The URL does not support the key #{key}")] end end class MissingKey < Error def errors [JSONAPI::Error.new(code: JSONAPI::KEY_ORDER_MISMATCH, - status: :bad_request, - title: 'A key is required', - detail: 'The resource object does not contain a key.')] + status: :bad_request, + title: 'A key is required', + detail: 'The resource object does not contain a key.')] end end @@ -289,9 +287,9 @@ def initialize(message) def errors [JSONAPI::Error.new(code: JSONAPI::LOCKED, - status: :locked, - title: 'Locked resource', - detail: "#{message}")] + status: :locked, + title: 'Locked resource', + detail: "#{message}")] end end @@ -339,7 +337,6 @@ def errors end end - class PageParametersNotAllowed < Error attr_accessor :params def initialize(params) @@ -347,13 +344,12 @@ def initialize(params) end def errors - params.collect { |param| + params.collect do |param| JSONAPI::Error.new(code: JSONAPI::PARAM_NOT_ALLOWED, status: :bad_request, title: 'Page parameter not allowed', detail: "#{param} is not an allowed page parameter.") - } - + end end end diff --git a/lib/jsonapi/include_directives.rb b/lib/jsonapi/include_directives.rb index b1d50eb08..ee51b2085 100644 --- a/lib/jsonapi/include_directives.rb +++ b/lib/jsonapi/include_directives.rb @@ -1,18 +1,17 @@ module JSONAPI class IncludeDirectives - # Construct an IncludeDirectives Hash from an array of dot separated include strings. # For example ['posts.comments.tags'] # will transform into => # { - # :posts=>{ - # :include=>true, - # :include_related=>{ - # :comments=>{ - # :include=>true, - # :include_related=>{ - # :tags=>{ - # :include=>true + # posts:{ + # include:true, + # include_related:{ + # comments:{ + # include:true, + # include_related:{ + # tags:{ + # include:true # } # } # } @@ -21,7 +20,7 @@ class IncludeDirectives # } def initialize(includes_array) - @include_directives_hash = {include_related: {}} + @include_directives_hash = { include_related: {} } includes_array.each do |include| parse_include(include) end @@ -36,11 +35,12 @@ def model_includes end private + def get_related(current_path) current = @include_directives_hash current_path.split('.').each do |fragment| fragment = fragment.to_sym - current[:include_related][fragment] ||= {include: false, include_related: {}} + current[:include_related][fragment] ||= { include: false, include_related: {} } current = current[:include_related][fragment] end current diff --git a/lib/jsonapi/mime_types.rb b/lib/jsonapi/mime_types.rb index 6a8426c0f..08a1290d7 100644 --- a/lib/jsonapi/mime_types.rb +++ b/lib/jsonapi/mime_types.rb @@ -1,9 +1,9 @@ module JSONAPI - MEDIA_TYPE = "application/vnd.api+json" + MEDIA_TYPE = 'application/vnd.api+json' end Mime::Type.register JSONAPI::MEDIA_TYPE, :api_json -ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime::Type.lookup(JSONAPI::MEDIA_TYPE)]=lambda do |body| +ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime::Type.lookup(JSONAPI::MEDIA_TYPE)] = lambda do |body| JSON.parse(body) end diff --git a/lib/jsonapi/operation.rb b/lib/jsonapi/operation.rb index d0e2ad36f..753b7823e 100644 --- a/lib/jsonapi/operation.rb +++ b/lib/jsonapi/operation.rb @@ -27,8 +27,8 @@ def initialize(resource_klass, options = {}) def record_count @_record_count ||= @resource_klass.find_count(@resource_klass.verify_filters(@filters, @context), - context: @context, - include_directives: @include_directives) + context: @context, + include_directives: @include_directives) end def pagination_params @@ -43,10 +43,10 @@ def pagination_params def apply resource_records = @resource_klass.find(@resource_klass.verify_filters(@filters, @context), - context: @context, - include_directives: @include_directives, - sort_criteria: @sort_criteria, - paginator: @paginator) + context: @context, + include_directives: @include_directives, + sort_criteria: @sort_criteria, + paginator: @paginator) options = {} if JSONAPI.configuration.top_level_links_include_pagination @@ -153,11 +153,9 @@ def apply source_resource = @source_klass.find_by_key(@source_id, context: @context) related_resource = source_resource.send(@association_type, - { - filters: @filters, - sort_criteria: @sort_criteria, - paginator: @paginator - }) + filters: @filters, + sort_criteria: @sort_criteria, + paginator: @paginator) return JSONAPI::ResourceOperationResult.new(:ok, related_resource) @@ -216,7 +214,7 @@ def apply resource = @resource_klass.find_by_key(@resource_id, context: @context) result = resource.replace_fields(data) - return JSONAPI::ResourceOperationResult.new(result == :completed ? :ok : :accepted, resource) + JSONAPI::ResourceOperationResult.new(result == :completed ? :ok : :accepted, resource) end end @@ -234,7 +232,7 @@ def apply resource = @resource_klass.find_by_key(@resource_id, context: @context) result = resource.replace_has_one_link(@association_type, @key_value) - return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted) + JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted) end end @@ -252,7 +250,7 @@ def apply resource = @resource_klass.find_by_key(@resource_id, context: @context) result = resource.create_has_many_links(@association_type, @data) - return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted) + JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted) end end @@ -270,7 +268,7 @@ def apply resource = @resource_klass.find_by_key(@resource_id, context: @context) result = resource.replace_has_many_links(@association_type, @data) - return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted) + JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted) end end @@ -288,7 +286,7 @@ def apply resource = @resource_klass.find_by_key(@resource_id, context: @context) result = resource.remove_has_many_link(@association_type, @associated_key) - return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted) + JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted) end end @@ -305,7 +303,7 @@ def apply resource = @resource_klass.find_by_key(@resource_id, context: @context) result = resource.remove_has_one_link(@association_type) - return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted) + JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted) end end end diff --git a/lib/jsonapi/operations_processor.rb b/lib/jsonapi/operations_processor.rb index 1dd2376d9..ceddde937 100644 --- a/lib/jsonapi/operations_processor.rb +++ b/lib/jsonapi/operations_processor.rb @@ -34,7 +34,7 @@ def process(request) @transactional = false if @operations.length > 1 @operations.each do |operation| - @transactional = @transactional | operation.transactional + @transactional |= operation.transactional end end @@ -56,9 +56,7 @@ def process(request) @result.meta.merge!(@operation_meta) @result.links.merge!(@operation_links) @results.add_result(@result) - if @results.has_errors? - rollback - end + rollback if @results.has_errors? end end @results.meta = @operations_meta @@ -99,4 +97,4 @@ def process_operation(operation) end class BasicOperationsProcessor < JSONAPI::OperationsProcessor -end \ No newline at end of file +end diff --git a/lib/jsonapi/paginator.rb b/lib/jsonapi/paginator.rb index 514b5bebe..6f47b71fb 100644 --- a/lib/jsonapi/paginator.rb +++ b/lib/jsonapi/paginator.rb @@ -1,13 +1,13 @@ module JSONAPI class Paginator - def initialize(params) + def initialize(_params) end - def apply(relation, order_options) + def apply(_relation, _order_options) # relation end - def links_page_params(options = {}) + def links_page_params(_options = {}) # :nocov: {} # :nocov: @@ -40,7 +40,7 @@ def self.requires_record_count true end - def apply(relation, order_options) + def apply(relation, _order_options) relation.offset(@offset).limit(@limit) end @@ -56,9 +56,7 @@ def links_page_params(options = {}) if @offset > 0 previous_offset = @offset - @limit - if previous_offset < 0 - previous_offset = 0 - end + previous_offset = 0 if previous_offset < 0 links_page_params['previous'] = { 'offset' => previous_offset, @@ -71,7 +69,7 @@ def links_page_params(options = {}) unless next_offset >= record_count links_page_params['next'] = { 'offset' => next_offset, - 'limit'=> @limit + 'limit' => @limit } end @@ -86,6 +84,7 @@ def links_page_params(options = {}) end private + def parse_pagination_params(params) if params.nil? @offset = 0 @@ -96,7 +95,7 @@ def parse_pagination_params(params) @offset = validparams[:offset] ? validparams[:offset].to_i : 0 @limit = validparams[:limit] ? validparams[:limit].to_i : JSONAPI.configuration.default_page_size else - raise JSONAPI::Exceptions::InvalidPageObject.new + fail JSONAPI::Exceptions::InvalidPageObject.new end rescue ActionController::UnpermittedParameters => e raise JSONAPI::Exceptions::PageParametersNotAllowed.new(e.params) @@ -104,14 +103,14 @@ def parse_pagination_params(params) def verify_pagination_params if @limit < 1 - raise JSONAPI::Exceptions::InvalidPageValue.new(:limit, @limit) + fail JSONAPI::Exceptions::InvalidPageValue.new(:limit, @limit) elsif @limit > JSONAPI.configuration.maximum_page_size - raise JSONAPI::Exceptions::InvalidPageValue.new(:limit, @limit, - "Limit exceeds maximum page size of #{JSONAPI.configuration.maximum_page_size}.") + fail JSONAPI::Exceptions::InvalidPageValue.new(:limit, @limit, + "Limit exceeds maximum page size of #{JSONAPI.configuration.maximum_page_size}.") end if @offset < 0 - raise JSONAPI::Exceptions::InvalidPageValue.new(:offset, @offset) + fail JSONAPI::Exceptions::InvalidPageValue.new(:offset, @offset) end end end @@ -128,7 +127,7 @@ def self.requires_record_count true end - def apply(relation, order_options) + def apply(relation, _order_options) offset = (@number - 1) * @size relation.offset(offset).limit(@size) end @@ -154,7 +153,7 @@ def links_page_params(options = {}) unless @number >= page_count links_page_params['next'] = { 'number' => @number + 1, - 'size'=> @size + 'size' => @size } end @@ -169,6 +168,7 @@ def links_page_params(options = {}) end private + def parse_pagination_params(params) if params.nil? @number = 1 @@ -188,14 +188,14 @@ def parse_pagination_params(params) def verify_pagination_params if @size < 1 - raise JSONAPI::Exceptions::InvalidPageValue.new(:size, @size) + fail JSONAPI::Exceptions::InvalidPageValue.new(:size, @size) elsif @size > JSONAPI.configuration.maximum_page_size - raise JSONAPI::Exceptions::InvalidPageValue.new(:size, @size, - "size exceeds maximum page size of #{JSONAPI.configuration.maximum_page_size}.") + fail JSONAPI::Exceptions::InvalidPageValue.new(:size, @size, + "size exceeds maximum page size of #{JSONAPI.configuration.maximum_page_size}.") end if @number < 1 - raise JSONAPI::Exceptions::InvalidPageValue.new(:number, @number) + fail JSONAPI::Exceptions::InvalidPageValue.new(:number, @number) end end end diff --git a/lib/jsonapi/request.rb b/lib/jsonapi/request.rb index 7981d00a5..5f8e055ff 100644 --- a/lib/jsonapi/request.rb +++ b/lib/jsonapi/request.rb @@ -15,7 +15,7 @@ def initialize(params = nil, options = {}) @operations = [] @fields = {} @filters = {} - @sort_criteria = [{field: 'id', direction: :asc}] + @sort_criteria = [{ field: 'id', direction: :asc }] @source_klass = nil @source_id = nil @include_directives = nil @@ -111,7 +111,7 @@ def setup_destroy_action(params) parse_remove_operation(params) end - def setup_destroy_association_action (params) + def setup_destroy_association_action(params) parse_remove_association_operation(params) end @@ -139,7 +139,7 @@ def parse_fields(fields) extracted_fields[field] = resource_fields end else - raise JSONAPI::Exceptions::InvalidFieldFormat.new + fail JSONAPI::Exceptions::InvalidFieldFormat.new end # Validate the fields @@ -148,13 +148,13 @@ def parse_fields(fields) extracted_fields[type] = [] begin if type != format_key(type) - raise JSONAPI::Exceptions::InvalidResource.new(type) + fail JSONAPI::Exceptions::InvalidResource.new(type) end type_resource = Resource.resource_for(@resource_klass.module_path + underscored_type.to_s) rescue NameError @errors.concat(JSONAPI::Exceptions::InvalidResource.new(type).errors) rescue JSONAPI::Exceptions::InvalidResource => e - @errors.concat(e.errors) + @errors.concat(e.errors) end if type_resource.nil? || !(@resource_klass._type == underscored_type || @@ -189,7 +189,7 @@ def check_include(resource_klass, include_parts) end else @errors.concat(JSONAPI::Exceptions::InvalidInclude.new(format_key(resource_klass._type), - include_parts.first,).errors) + include_parts.first).errors) end end @@ -238,10 +238,10 @@ def parse_sort_criteria(sort_criteria) @sort_criteria = CSV.parse_line(URI.unescape(sort_criteria)).collect do |sort| if sort.start_with?('-') - sort_criteria = {field: unformat_key(sort[1..-1]).to_s} + sort_criteria = { field: unformat_key(sort[1..-1]).to_s } sort_criteria[:direction] = :desc else - sort_criteria = {field: unformat_key(sort).to_s} + sort_criteria = { field: unformat_key(sort).to_s } sort_criteria[:direction] = :asc end @@ -262,64 +262,54 @@ def check_sort_criteria(resource_klass, sort_criteria) def add_find_operation @operations.push JSONAPI::FindOperation.new( - @resource_klass, - { - context: @context, - filters: @filters, - include_directives: @include_directives, - sort_criteria: @sort_criteria, - paginator: @paginator - } - ) + @resource_klass, + context: @context, + filters: @filters, + include_directives: @include_directives, + sort_criteria: @sort_criteria, + paginator: @paginator + ) end def add_show_operation @operations.push JSONAPI::ShowOperation.new( - @resource_klass, - { - context: @context, - id: @id, - include_directives: @include_directives - } - ) + @resource_klass, + context: @context, + id: @id, + include_directives: @include_directives + ) end def add_show_association_operation(association_type, parent_key) @operations.push JSONAPI::ShowAssociationOperation.new( - @resource_klass, - { - context: @context, - association_type: association_type, - parent_key: @resource_klass.verify_key(parent_key) - } - ) + @resource_klass, + context: @context, + association_type: association_type, + parent_key: @resource_klass.verify_key(parent_key) + ) end def add_show_related_resource_operation(association_type) @operations.push JSONAPI::ShowRelatedResourceOperation.new( - @resource_klass, - { - context: @context, - association_type: association_type, - source_klass: @source_klass, - source_id: @source_id - } - ) + @resource_klass, + context: @context, + association_type: association_type, + source_klass: @source_klass, + source_id: @source_id + ) end def add_show_related_resources_operation(association_type) @operations.push JSONAPI::ShowRelatedResourcesOperation.new( - @resource_klass, - { - context: @context, - association_type: association_type, - source_klass: @source_klass, - source_id: @source_id, - filters: @source_klass.verify_filters(@filters, @context), - sort_criteria: @sort_criteria, - paginator: @paginator - } - ) + @resource_klass, + context: @context, + association_type: association_type, + source_klass: @source_klass, + source_id: @source_id, + filters: @source_klass.verify_filters(@filters, @context), + sort_criteria: @sort_criteria, + paginator: @paginator + ) end # TODO: Please remove after `createable_fields` is removed @@ -339,12 +329,10 @@ def parse_add_operation(data) data = parse_params(params, creatable_fields) @operations.push JSONAPI::CreateResourceOperation.new( - @resource_klass, - { - context: @context, - data: data - } - ) + @resource_klass, + context: @context, + data: data + ) end rescue JSONAPI::Exceptions::Error => e @errors.concat(e.errors) @@ -352,9 +340,9 @@ def parse_add_operation(data) def verify_type(type) if type.nil? - raise JSONAPI::Exceptions::ParameterMissing.new(:type) + fail JSONAPI::Exceptions::ParameterMissing.new(:type) elsif unformat_key(type).to_sym != @resource_klass._type - raise JSONAPI::Exceptions::InvalidResource.new(type) + fail JSONAPI::Exceptions::InvalidResource.new(type) end end @@ -366,8 +354,8 @@ def parse_has_one_links_object(raw) } end - if !raw.is_a?(Hash) || raw.length != 2 || !(raw.has_key?('type') && raw.has_key?('id')) - raise JSONAPI::Exceptions::InvalidLinksObject.new + if !raw.is_a?(Hash) || raw.length != 2 || !(raw.key?('type') && raw.key?('id')) + fail JSONAPI::Exceptions::InvalidLinksObject.new end { @@ -377,9 +365,7 @@ def parse_has_one_links_object(raw) end def parse_has_many_links_object(raw) - if raw.nil? - raise JSONAPI::Exceptions::InvalidLinksObject.new - end + fail JSONAPI::Exceptions::InvalidLinksObject.new if raw.nil? links_object = {} if raw.is_a?(Array) @@ -389,7 +375,7 @@ def parse_has_many_links_object(raw) links_object[link_object[:type]].push(link_object[:id]) end else - raise JSONAPI::Exceptions::InvalidLinksObject.new + fail JSONAPI::Exceptions::InvalidLinksObject.new end links_object end @@ -403,73 +389,73 @@ def parse_params(params, allowed_fields) params.each do |key, value| case key.to_s - when 'relationships' - value.each do |link_key, link_value| - param = unformat_key(link_key) + when 'relationships' + value.each do |link_key, link_value| + param = unformat_key(link_key) - association = @resource_klass._association(param) + association = @resource_klass._association(param) - if association.is_a?(JSONAPI::Association::HasOne) - if link_value.nil? - linkage = nil - else - linkage = link_value[:data] - end + if association.is_a?(JSONAPI::Association::HasOne) + if link_value.nil? + linkage = nil + else + linkage = link_value[:data] + end - links_object = parse_has_one_links_object(linkage) - # Since we do not yet support polymorphic associations we will raise an error if the type does not match the - # association's type. - # ToDo: Support Polymorphic associations - if links_object[:type] && (links_object[:type].to_s != association.type.to_s) - raise JSONAPI::Exceptions::TypeMismatch.new(links_object[:type]) - end + links_object = parse_has_one_links_object(linkage) + # Since we do not yet support polymorphic associations we will raise an error if the type does not match the + # association's type. + # TODO: Support Polymorphic associations + if links_object[:type] && (links_object[:type].to_s != association.type.to_s) + fail JSONAPI::Exceptions::TypeMismatch.new(links_object[:type]) + end - unless links_object[:id].nil? - association_resource = Resource.resource_for(@resource_klass.module_path + unformat_key(links_object[:type]).to_s) - checked_has_one_associations[param] = association_resource.verify_key(links_object[:id], @context) - else - checked_has_one_associations[param] = nil - end - elsif association.is_a?(JSONAPI::Association::HasMany) - if link_value.is_a?(Array) && link_value.length == 0 - linkage = [] - elsif link_value.is_a?(Hash) - linkage = link_value[:data] - else - raise JSONAPI::Exceptions::InvalidLinksObject.new - end + unless links_object[:id].nil? + association_resource = Resource.resource_for(@resource_klass.module_path + unformat_key(links_object[:type]).to_s) + checked_has_one_associations[param] = association_resource.verify_key(links_object[:id], @context) + else + checked_has_one_associations[param] = nil + end + elsif association.is_a?(JSONAPI::Association::HasMany) + if link_value.is_a?(Array) && link_value.length == 0 + linkage = [] + elsif link_value.is_a?(Hash) + linkage = link_value[:data] + else + fail JSONAPI::Exceptions::InvalidLinksObject.new + end - links_object = parse_has_many_links_object(linkage) + links_object = parse_has_many_links_object(linkage) - # Since we do not yet support polymorphic associations we will raise an error if the type does not match the - # association's type. - # ToDo: Support Polymorphic associations + # Since we do not yet support polymorphic associations we will raise an error if the type does not match the + # association's type. + # TODO: Support Polymorphic associations - if links_object.length == 0 - checked_has_many_associations[param] = [] - else - if links_object.length > 1 || !links_object.has_key?(unformat_key(association.type).to_s) - raise JSONAPI::Exceptions::TypeMismatch.new(links_object[:type]) - end + if links_object.length == 0 + checked_has_many_associations[param] = [] + else + if links_object.length > 1 || !links_object.key?(unformat_key(association.type).to_s) + fail JSONAPI::Exceptions::TypeMismatch.new(links_object[:type]) + end - links_object.each_pair do |type, keys| - association_resource = Resource.resource_for(@resource_klass.module_path + unformat_key(type).to_s) - checked_has_many_associations[param] = association_resource.verify_keys(keys, @context) - end + links_object.each_pair do |type, keys| + association_resource = Resource.resource_for(@resource_klass.module_path + unformat_key(type).to_s) + checked_has_many_associations[param] = association_resource.verify_keys(keys, @context) end end end - when 'id' - checked_attributes['id'] = unformat_value(:id, value) - when 'attributes' - value.each do |key, value| - param = unformat_key(key) - checked_attributes[param] = unformat_value(param, value) - end + end + when 'id' + checked_attributes['id'] = unformat_value(:id, value) + when 'attributes' + value.each do |key, value| + param = unformat_key(key) + checked_attributes[param] = unformat_value(param, value) + end end end - return { + { 'attributes' => checked_attributes, 'has_one' => checked_has_one_associations, 'has_many' => checked_has_many_associations @@ -487,21 +473,21 @@ def verify_permitted_params(params, allowed_fields) params.each do |key, value| case key.to_s - when 'relationships' - value.each_key do |links_key| - params_not_allowed.push(links_key) unless formatted_allowed_fields.include?(links_key.to_sym) - end - when 'attributes' - value.each do |attr_key, attr_value| - params_not_allowed.push(attr_key) unless formatted_allowed_fields.include?(attr_key.to_sym) - end - when 'type', 'id' - else - params_not_allowed.push(key) + when 'relationships' + value.each_key do |links_key| + params_not_allowed.push(links_key) unless formatted_allowed_fields.include?(links_key.to_sym) + end + when 'attributes' + value.each do |attr_key, _attr_value| + params_not_allowed.push(attr_key) unless formatted_allowed_fields.include?(attr_key.to_sym) + end + when 'type', 'id' + else + params_not_allowed.push(key) end end - raise JSONAPI::Exceptions::ParametersNotAllowed.new(params_not_allowed) if params_not_allowed.length > 0 + fail JSONAPI::Exceptions::ParametersNotAllowed.new(params_not_allowed) if params_not_allowed.length > 0 end # TODO: Please remove after `updateable_fields` is removed @@ -519,18 +505,16 @@ def parse_add_association_operation(data, association_type, parent_key) association = resource_klass._association(association_type) if association.is_a?(JSONAPI::Association::HasMany) - object_params = {relationships: {format_key(association.name) => {data: data}}} + object_params = { relationships: { format_key(association.name) => { data: data } } } verified_param_set = parse_params(object_params, updatable_fields) @operations.push JSONAPI::CreateHasManyAssociationOperation.new( - resource_klass, - { - context: @context, - resource_id: parent_key, - association_type: association_type, - data: verified_param_set[:has_many].values[0] - } - ) + resource_klass, + context: @context, + resource_id: parent_key, + association_type: association_type, + data: verified_param_set[:has_many].values[0] + ) end end @@ -538,74 +522,62 @@ def parse_update_association_operation(data, association_type, parent_key) association = resource_klass._association(association_type) if association.is_a?(JSONAPI::Association::HasOne) - object_params = {relationships: {format_key(association.name) => {data: data}}} + object_params = { relationships: { format_key(association.name) => { data: data } } } verified_param_set = parse_params(object_params, updatable_fields) @operations.push JSONAPI::ReplaceHasOneAssociationOperation.new( - resource_klass, - { - context: @context, - resource_id: parent_key, - association_type: association_type, - key_value: verified_param_set[:has_one].values[0] - } - ) + resource_klass, + context: @context, + resource_id: parent_key, + association_type: association_type, + key_value: verified_param_set[:has_one].values[0] + ) else unless association.acts_as_set - raise JSONAPI::Exceptions::HasManySetReplacementForbidden.new + fail JSONAPI::Exceptions::HasManySetReplacementForbidden.new end - object_params = {relationships: {format_key(association.name) => {data: data}}} + object_params = { relationships: { format_key(association.name) => { data: data } } } verified_param_set = parse_params(object_params, updatable_fields) @operations.push JSONAPI::ReplaceHasManyAssociationOperation.new( - resource_klass, - { - context: @context, - resource_id: parent_key, - association_type: association_type, - data: verified_param_set[:has_many].values[0] - } - ) + resource_klass, + context: @context, + resource_id: parent_key, + association_type: association_type, + data: verified_param_set[:has_many].values[0] + ) end end def parse_single_replace_operation(data, keys) - if data[:id].nil? - raise JSONAPI::Exceptions::MissingKey.new - end + fail JSONAPI::Exceptions::MissingKey.new if data[:id].nil? type = data[:type] if type.nil? || type != format_key(@resource_klass._type).to_s - raise JSONAPI::Exceptions::ParameterMissing.new(:type) + fail JSONAPI::Exceptions::ParameterMissing.new(:type) end key = data[:id] - if !keys.include?(key) - raise JSONAPI::Exceptions::KeyNotIncludedInURL.new(key) + unless keys.include?(key) + fail JSONAPI::Exceptions::KeyNotIncludedInURL.new(key) end - if !keys.include?(:id) - data.delete(:id) - end + data.delete(:id) unless keys.include?(:id) verify_type(data[:type]) @operations.push JSONAPI::ReplaceFieldsOperation.new( - @resource_klass, - { - context: @context, - resource_id: key, - data: parse_params(data, updatable_fields) - } - ) + @resource_klass, + context: @context, + resource_id: key, + data: parse_params(data, updatable_fields) + ) end def parse_replace_operation(data, keys) if data.is_a?(Array) - if keys.count != data.count - raise JSONAPI::Exceptions::CountMismatch - end + fail JSONAPI::Exceptions::CountMismatch if keys.count != data.count data.each do |object_params| parse_single_replace_operation(object_params, keys) @@ -623,12 +595,10 @@ def parse_remove_operation(params) keys.each do |key| @operations.push JSONAPI::RemoveResourceOperation.new( - @resource_klass, - { - context: @context, - resource_id: key - } - ) + @resource_klass, + context: @context, + resource_id: key + ) end rescue ActionController::UnpermittedParameters => e @errors.concat(JSONAPI::Exceptions::ParametersNotAllowed.new(e.params).errors) @@ -646,29 +616,25 @@ def parse_remove_association_operation(params) keys = parse_key_array(params[:keys]) keys.each do |key| @operations.push JSONAPI::RemoveHasManyAssociationOperation.new( - resource_klass, - { - context: @context, - resource_id: parent_key, - association_type: association_type, - associated_key: key - } - ) + resource_klass, + context: @context, + resource_id: parent_key, + association_type: association_type, + associated_key: key + ) end else @operations.push JSONAPI::RemoveHasOneAssociationOperation.new( - resource_klass, - { - context: @context, - resource_id: parent_key, - association_type: association_type - } - ) + resource_klass, + context: @context, + resource_id: parent_key, + association_type: association_type + ) end end def parse_key_array(raw) - return @resource_klass.verify_keys(raw.split(/,/), context) + @resource_klass.verify_keys(raw.split(/,/), context) end def format_key(key) diff --git a/lib/jsonapi/resource.rb b/lib/jsonapi/resource.rb index 4d299f1ce..a32490471 100644 --- a/lib/jsonapi/resource.rb +++ b/lib/jsonapi/resource.rb @@ -6,7 +6,7 @@ class Resource @@resource_types = {} - attr :context + attr_reader :context attr_reader :model define_jsonapi_resources_callbacks :create, @@ -48,13 +48,11 @@ def change(callback) completed = (yield == :completed) end - if @save_needed || is_new? - completed = (save == :completed) - end + completed = (save == :completed) if @save_needed || is_new? end end - return completed ? :completed : :accepted + completed ? :completed : :accepted end def remove @@ -106,11 +104,12 @@ def fetchable_fields # Override this on a resource to customize how the associated records # are fetched for a model. Particularly helpful for authorization. - def records_for(association_name, options = {}) + def records_for(association_name, _options = {}) model.send association_name end private + def save run_callbacks :save do _save @@ -132,27 +131,25 @@ def save # ``` def _save unless @model.valid? - raise JSONAPI::Exceptions::ValidationErrors.new(@model.errors.messages) + fail JSONAPI::Exceptions::ValidationErrors.new(@model.errors.messages) end if defined? @model.save saved = @model.save - unless saved - raise JSONAPI::Exceptions::SaveFailed.new - end + fail JSONAPI::Exceptions::SaveFailed.new unless saved else saved = true end @save_needed = !saved - return :completed + :completed end def _remove @model.destroy - return :completed + :completed end def _create_has_many_links(association_type, association_key_values) @@ -161,16 +158,16 @@ def _create_has_many_links(association_type, association_key_values) association_key_values.each do |association_key_value| related_resource = Resource.resource_for(self.class.module_path + association.type.to_s).find_by_key(association_key_value, context: @context) - # ToDo: Add option to skip relations that already exist instead of returning an error? + # TODO: Add option to skip relations that already exist instead of returning an error? relation = @model.send(association.type).where(association.primary_key => association_key_value).first if relation.nil? @model.send(association.type) << related_resource.model else - raise JSONAPI::Exceptions::HasManyRelationExists.new(association_key_value) + fail JSONAPI::Exceptions::HasManyRelationExists.new(association_key_value) end end - return :completed + :completed end def _replace_has_many_links(association_type, association_key_values) @@ -179,7 +176,7 @@ def _replace_has_many_links(association_type, association_key_values) send("#{association.foreign_key}=", association_key_values) @save_needed = true - return :completed + :completed end def _replace_has_one_link(association_type, association_key_value) @@ -188,7 +185,7 @@ def _replace_has_one_link(association_type, association_key_value) send("#{association.foreign_key}=", association_key_value) @save_needed = true - return :completed + :completed end def _remove_has_many_link(association_type, key) @@ -196,7 +193,7 @@ def _remove_has_many_link(association_type, key) @model.send(association.type).delete(key) - return :completed + :completed end def _remove_has_one_link(association_type) @@ -205,7 +202,7 @@ def _remove_has_one_link(association_type) send("#{association.foreign_key}=", nil) @save_needed = true - return :completed + :completed end def _replace_fields(field_data) @@ -232,7 +229,7 @@ def _replace_fields(field_data) replace_has_many_links(association_type, values) end if field_data[:has_many] - return :completed + :completed end class << self @@ -253,15 +250,15 @@ def resource_for(type) resource_name = JSONAPI::Resource._resource_name_from_type(type) resource = resource_name.safe_constantize if resource_name if resource.nil? - raise NameError, "JSONAPI: Could not find resource '#{type}'. (Class #{resource_name} not found)" + fail NameError, "JSONAPI: Could not find resource '#{type}'. (Class #{resource_name} not found)" end resource end - attr_accessor :_attributes, :_associations, :_allowed_filters , :_type, :_paginator + attr_accessor :_attributes, :_associations, :_allowed_filters, :_type, :_paginator def create(context) - self.new(self.create_model, context) + new(create_model, context) end def create_model @@ -303,7 +300,7 @@ def attribute(attr, options = {}) end def default_attribute_options - {format: :default} + { format: :default } end def has_one(*attrs) @@ -319,7 +316,7 @@ def model_name(model) end def filters(*attrs) - @_allowed_filters.merge!(attrs.inject( Hash.new ) { |h, attr| h[attr] = {}; h }) + @_allowed_filters.merge!(attrs.inject({}) { |h, attr| h[attr] = {}; h }) end def filter(attr, *args) @@ -334,11 +331,11 @@ def primary_key(key) # :nocov: def method_missing(method, *args) if method.to_s.match /createable_fields/ - ActiveSupport::Deprecation.warn("`createable_fields` is deprecated, please use `creatable_fields` instead") - self.creatable_fields(*args) + ActiveSupport::Deprecation.warn('`createable_fields` is deprecated, please use `creatable_fields` instead') + creatable_fields(*args) elsif method.to_s.match /updateable_fields/ - ActiveSupport::Deprecation.warn("`updateable_fields` is deprecated, please use `updatable_fields` instead") - self.updatable_fields(*args) + ActiveSupport::Deprecation.warn('`updateable_fields` is deprecated, please use `updatable_fields` instead') + updatable_fields(*args) else super end @@ -346,17 +343,17 @@ def method_missing(method, *args) # :nocov: # Override in your resource to filter the updatable keys - def updatable_fields(context = nil) + def updatable_fields(_context = nil) _updatable_associations | _attributes.keys - [:id] end # Override in your resource to filter the creatable keys - def creatable_fields(context = nil) + def creatable_fields(_context = nil) _updatable_associations | _attributes.keys end # Override in your resource to filter the sortable keys - def sortable_fields(context = nil) + def sortable_fields(_context = nil) _attributes.keys end @@ -370,9 +367,7 @@ def apply_includes(records, directives) end def apply_pagination(records, paginator, order_options) - if paginator - records = paginator.apply(records, order_options) - end + records = paginator.apply(records, order_options) if paginator records end @@ -384,7 +379,7 @@ def apply_sort(records, order_options) end end - def apply_filter(records, filter, value, options = {}) + def apply_filter(records, filter, value, _options = {}) records.where(filter => value) end @@ -445,10 +440,10 @@ def find(filters, options = {}) resources = [] records.each do |model| - resources.push self.new(model, context) + resources.push new(model, context) end - return resources + resources end def find_by_key(key, options = {}) @@ -456,16 +451,14 @@ def find_by_key(key, options = {}) include_directives = options[:include_directives] records = records(options) records = apply_includes(records, include_directives) - model = records.where({_primary_key => key}).first - if model.nil? - raise JSONAPI::Exceptions::RecordNotFound.new(key) - end - self.new(model, context) + model = records.where(_primary_key => key).first + fail JSONAPI::Exceptions::RecordNotFound.new(key) if model.nil? + new(model, context) end # Override this method if you want to customize the relation for # finder methods (find, find_by_key) - def records(options = {}) + def records(_options = {}) _model_class end @@ -494,7 +487,7 @@ def verify_filter(filter, raw, context = nil) end # override to allow for key processing and checking - def verify_key(key, context = nil) + def verify_key(key, _context = nil) key && Integer(key) rescue raise JSONAPI::Exceptions::InvalidFieldValue.new(:id, key) @@ -502,19 +495,19 @@ def verify_key(key, context = nil) # override to allow for key processing and checking def verify_keys(keys, context = nil) - return keys.collect do |key| + keys.collect do |key| verify_key(key, context) end end # override to allow for custom filters - def verify_custom_filter(filter, value, context = nil) - return filter, value + def verify_custom_filter(filter, value, _context = nil) + [filter, value] end # override to allow for custom association logic, such as uuids, multiple keys or permission checks on keys - def verify_association_filter(filter, raw, context = nil) - return filter, raw + def verify_association_filter(filter, raw, _context = nil) + [filter, raw] end # quasi private class methods @@ -523,12 +516,12 @@ def _attribute_options(attr) end def _updatable_associations - @_associations.map { |key, association| key } + @_associations.map { |key, _association| key } end def _has_association?(type) type = type.to_s - @_associations.has_key?(type.singularize.to_sym) || @_associations.has_key?(type.pluralize.to_sym) + @_associations.key?(type.singularize.to_sym) || @_associations.key?(type.pluralize.to_sym) end def _association(type) @@ -537,7 +530,7 @@ def _association(type) end def _model_name - @_model_name ||= self.name.demodulize.sub(/Resource$/, '') + @_model_name ||= name.demodulize.sub(/Resource$/, '') end def _primary_key @@ -549,7 +542,7 @@ def _as_parent_key end def _allowed_filters - !@_allowed_filters.nil? ? @_allowed_filters : { :id => {} } + !@_allowed_filters.nil? ? @_allowed_filters : { id: {} } end def _resource_name_from_type(type) @@ -558,7 +551,7 @@ def _resource_name_from_type(type) class_name = "#{type.to_s.singularize}_resource".camelize @@resource_types[type] = class_name end - return class_name + class_name end def _paginator @@ -578,19 +571,20 @@ def _allowed_filter?(filter) end def module_path - @module_path ||= self.name =~ /::[^:]+\Z/ ? ($`.freeze.gsub('::', '/') + '/').downcase : '' + @module_path ||= name =~ /::[^:]+\Z/ ? ($`.freeze.gsub('::', '/') + '/').downcase : '' end def construct_order_options(sort_params) return {} unless sort_params - sort_params.each_with_object({}) { |sort, order_hash| + sort_params.each_with_object({}) do |sort, order_hash| field = sort[:field] == 'id' ? _primary_key : sort[:field] order_hash[field] = sort[:direction] - } + end end private + def check_reserved_resource_name(type, name) if [:ids, :types, :hrefs, :links].include?(type) warn "[NAME COLLISION] `#{name}` is a reserved resource name." @@ -632,11 +626,11 @@ def _associate(klass, *attrs) end unless method_defined?("#{foreign_key}=") associated_records_method_name = case @_associations[attr] - when JSONAPI::Association::HasOne then "record_for_#{attr}" - when JSONAPI::Association::HasMany then "records_for_#{attr}" + when JSONAPI::Association::HasOne then "record_for_#{attr}" + when JSONAPI::Association::HasMany then "records_for_#{attr}" end - define_method associated_records_method_name do |options={}| + define_method associated_records_method_name do |options = {}| records_for(attr, options) end unless method_defined?(associated_records_method_name) @@ -675,6 +669,5 @@ def _associate(klass, *attrs) end end end - end end diff --git a/lib/jsonapi/resource_serializer.rb b/lib/jsonapi/resource_serializer.rb index 83c568b29..ad6bebf29 100644 --- a/lib/jsonapi/resource_serializer.rb +++ b/lib/jsonapi/resource_serializer.rb @@ -1,6 +1,5 @@ module JSONAPI class ResourceSerializer - # Options can include # include: # Purpose: determines which objects will be side loaded with the source objects in a linked section @@ -45,7 +44,7 @@ def serialize_to_hash(source) end end - primary_hash = {data: is_resource_collection ? primary_objects : primary_objects[0]} + primary_hash = { data: is_resource_collection ? primary_objects : primary_objects[0] } primary_hash[:included] = included_objects if included_objects.size > 0 primary_hash @@ -72,6 +71,7 @@ def find_link(query_params) end private + # Process the primary source object(s). This will then serialize associated object recursively based on the # requested includes. Fields are controlled fields option for each resource type, such # as fields: { people: [:id, :email, :comments], posts: [:id, :title, :author], comments: [:id, :body, :post]} @@ -100,7 +100,7 @@ def object_hash(source, include_directives) obj_hash = {} id_format = source.class._attribute_options(:id)[:format] - #protect against ids that were declared as an attribute, but did not have a format set. + # protect against ids that were declared as an attribute, but did not have a format set. id_format = 'id' if id_format == :default obj_hash['id'] = format_value(source.id, id_format) @@ -115,7 +115,7 @@ def object_hash(source, include_directives) relationships = relationship_data(source, include_directives) obj_hash['relationships'] = relationships unless relationships.nil? || relationships.empty? - return obj_hash + obj_hash end def requested_fields(model) @@ -125,9 +125,7 @@ def requested_fields(model) def attribute_hash(source) requested = requested_fields(source.class._type) fields = source.fetchable_fields & source.class._attributes.keys.to_a - unless requested.nil? - fields = requested & fields - end + fields = requested & fields unless requested.nil? fields.each_with_object({}) do |name, hash| format = source.class._attribute_options(name)[:format] @@ -141,9 +139,7 @@ def relationship_data(source, include_directives) associations = source.class._associations requested = requested_fields(source.class._type) fields = associations.keys - unless requested.nil? - fields = requested & fields - end + fields = requested & fields unless requested.nil? field_set = Set.new(fields) @@ -217,7 +213,7 @@ def self_href(source) def already_serialized?(type, id) type = format_key(type) - return @included_objects.key?(type) && @included_objects[type].key?(id) + @included_objects.key?(type) && @included_objects[type].key?(id) end def format_route(route) @@ -248,7 +244,7 @@ def has_many_linkage(source, association) linkage = [] linkage_ids = foreign_key_value(source, association) linkage_ids.each do |linkage_id| - linkage.append({type: format_key(association.type), id: linkage_id}) + linkage.append(type: format_key(association.type), id: linkage_id) end linkage end @@ -301,16 +297,12 @@ def set_primary(type, id) def add_included_object(type, id, object_hash, primary = false) type = format_key(type) - unless @included_objects.key?(type) - @included_objects[type] = {} - end + @included_objects[type] = {} unless @included_objects.key?(type) if already_serialized?(type, id) - if primary - set_primary(type, id) - end + set_primary(type, id) if primary else - @included_objects[type].store(id, {primary: primary, object_hash: object_hash}) + @included_objects[type].store(id, primary: primary, object_hash: object_hash) end end diff --git a/lib/jsonapi/resources/version.rb b/lib/jsonapi/resources/version.rb index b968a6afa..401a9449c 100644 --- a/lib/jsonapi/resources/version.rb +++ b/lib/jsonapi/resources/version.rb @@ -1,5 +1,5 @@ module JSONAPI module Resources - VERSION = "0.4.2" + VERSION = '0.4.2' end -end \ No newline at end of file +end diff --git a/lib/jsonapi/response_document.rb b/lib/jsonapi/response_document.rb index 48537acff..7cd6d21c3 100644 --- a/lib/jsonapi/response_document.rb +++ b/lib/jsonapi/response_document.rb @@ -90,7 +90,7 @@ def top_level_links def results_to_hash if @operation_results.has_errors? - {errors: @operation_results.all_errors} + { errors: @operation_results.all_errors } else if @operation_results.results.length == 1 result = @operation_results.results[0] diff --git a/lib/jsonapi/routing_ext.rb b/lib/jsonapi/routing_ext.rb index 827aa5e9d..adae5de18 100644 --- a/lib/jsonapi/routing_ext.rb +++ b/lib/jsonapi/routing_ext.rb @@ -1,7 +1,6 @@ module ActionDispatch module Routing class Mapper - Resource.class_eval do def unformat_route(route) JSONAPI.configuration.route_formatter.unformat(route.to_s) @@ -17,7 +16,7 @@ def format_route(route) JSONAPI.configuration.route_formatter.format(route.to_s) end - def jsonapi_resource(*resources, &block) + def jsonapi_resource(*resources, &_block) @resource_type = resources.first res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type)) @@ -57,7 +56,7 @@ def jsonapi_relationships(options = {}) end end - def jsonapi_resources(*resources, &block) + def jsonapi_resources(*resources, &_block) @resource_type = resources.first res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type)) @@ -111,17 +110,17 @@ def jsonapi_link(*links) if methods.include?(:show) match "relationships/#{formatted_association_name}", controller: options[:controller], - action: 'show_association', association: link_type.to_s, via: [:get] + action: 'show_association', association: link_type.to_s, via: [:get] end if methods.include?(:update) match "relationships/#{formatted_association_name}", controller: options[:controller], - action: 'update_association', association: link_type.to_s, via: [:put, :patch] + action: 'update_association', association: link_type.to_s, via: [:put, :patch] end if methods.include?(:destroy) match "relationships/#{formatted_association_name}", controller: options[:controller], - action: 'destroy_association', association: link_type.to_s, via: [:delete] + action: 'destroy_association', association: link_type.to_s, via: [:delete] end end @@ -137,22 +136,22 @@ def jsonapi_links(*links) if methods.include?(:show) match "relationships/#{formatted_association_name}", controller: options[:controller], - action: 'show_association', association: link_type.to_s, via: [:get] + action: 'show_association', association: link_type.to_s, via: [:get] end if methods.include?(:create) match "relationships/#{formatted_association_name}", controller: options[:controller], - action: 'create_association', association: link_type.to_s, via: [:post] + action: 'create_association', association: link_type.to_s, via: [:post] end if methods.include?(:update) match "relationships/#{formatted_association_name}", controller: options[:controller], - action: 'update_association', association: link_type.to_s, via: [:put, :patch] + action: 'update_association', association: link_type.to_s, via: [:put, :patch] end if methods.include?(:destroy) match "relationships/#{formatted_association_name}/:keys", controller: options[:controller], - action: 'destroy_association', association: link_type.to_s, via: [:delete] + action: 'destroy_association', association: link_type.to_s, via: [:delete] end end @@ -167,10 +166,9 @@ def jsonapi_related_resource(*association) related_resource = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(association.class_name.underscore.pluralize)) options[:controller] ||= related_resource._type.to_s - match "#{formatted_association_name}", controller: options[:controller], - association: association.name, source: resource_type_with_module_prefix(source._type), - action: 'get_related_resource', via: [:get] + association: association.name, source: resource_type_with_module_prefix(source._type), + action: 'get_related_resource', via: [:get] end def jsonapi_related_resources(*association) @@ -185,14 +183,15 @@ def jsonapi_related_resources(*association) options[:controller] ||= related_resource._type.to_s match "#{formatted_association_name}", controller: options[:controller], - association: association.name, source: resource_type_with_module_prefix(source._type), - action: 'get_related_resources', via: [:get] + association: association.name, source: resource_type_with_module_prefix(source._type), + action: 'get_related_resources', via: [:get] end private + def resource_type_with_module_prefix(resource = nil) resource_name = resource || @scope[:jsonapi_resource] - [@scope[:module], resource_name].compact.collect(&:to_s).join("/") + [@scope[:module], resource_name].compact.collect(&:to_s).join('/') end end end diff --git a/test/controllers/controller_test.rb b/test/controllers/controller_test.rb index 06998d58d..cbf494e42 100644 --- a/test/controllers/controller_test.rb +++ b/test/controllers/controller_test.rb @@ -76,10 +76,10 @@ def test_index_filter_by_ids_and_fields # type, id, links, attributes, relationships assert_equal 5, json_response['data'][0].size - assert json_response['data'][0].has_key?('type') - assert json_response['data'][0].has_key?('id') - assert json_response['data'][0]['attributes'].has_key?('title') - assert json_response['data'][0].has_key?('links') + assert json_response['data'][0].key?('type') + assert json_response['data'][0].key?('id') + assert json_response['data'][0]['attributes'].key?('title') + assert json_response['data'][0].key?('links') end def test_index_filter_by_ids_and_fields_specify_type @@ -89,10 +89,10 @@ def test_index_filter_by_ids_and_fields_specify_type # type, id, links, attributes, relationships assert_equal 5, json_response['data'][0].size - assert json_response['data'][0].has_key?('type') - assert json_response['data'][0].has_key?('id') - assert json_response['data'][0]['attributes'].has_key?('title') - assert json_response['data'][0].has_key?('links') + assert json_response['data'][0].key?('type') + assert json_response['data'][0].key?('id') + assert json_response['data'][0]['attributes'].key?('title') + assert json_response['data'][0].key?('links') end def test_index_filter_by_ids_and_fields_specify_unrelated_type @@ -108,9 +108,9 @@ def test_index_filter_by_ids_and_fields_2 # type, id, links, relationships assert_equal 4, json_response['data'][0].size - assert json_response['data'][0].has_key?('type') - assert json_response['data'][0].has_key?('id') - assert json_response['data'][0]['relationships'].has_key?('author') + assert json_response['data'][0].key?('type') + assert json_response['data'][0].key?('id') + assert json_response['data'][0]['relationships'].key?('author') end def test_filter_association_single @@ -236,7 +236,6 @@ def test_show_does_not_include_records_count_in_meta JSONAPI.configuration.top_level_meta_include_record_count = false end - def test_show_single_with_includes get :show, {id: '1', include: 'comments'} assert_response :success @@ -327,7 +326,7 @@ def test_create_link_to_missing_object } assert_response :unprocessable_entity - # Todo: check if this validation is working + # TODO: check if this validation is working assert_match /author - can't be blank/, response.body end @@ -1550,7 +1549,7 @@ def test_expense_entries_show_fields get :show, {id: 1, include: 'isoCurrency,employee', 'fields' => {'expenseEntries' => 'transactionDate'}} assert_response :success assert json_response['data'].is_a?(Hash) - assert json_response['data']['attributes'].has_key?('transactionDate') + assert json_response['data']['attributes'].key?('transactionDate') assert_equal 2, json_response['included'].size end @@ -1559,7 +1558,7 @@ def test_expense_entries_show_fields_type_many 'isoCurrencies' => 'id,name'}} assert_response :success assert json_response['data'].is_a?(Hash) - assert json_response['data']['attributes'].has_key?('transactionDate') + assert json_response['data']['attributes'].key?('transactionDate') assert_equal 2, json_response['included'].size end @@ -1895,7 +1894,7 @@ def test_valid_filter_value def test_get_related_resource JSONAPI.configuration.json_key_format = :dasherized_key JSONAPI.configuration.route_format = :underscored_key - get :get_related_resource, {post_id: '2', association: 'author', :source=>'posts'} + get :get_related_resource, {post_id: '2', association: 'author', source:'posts'} assert_response :success assert_hash_equals( { @@ -1948,7 +1947,7 @@ def test_get_related_resource end def test_get_related_resource_nil - get :get_related_resource, {post_id: '17', association: 'author', :source=>'posts'} + get :get_related_resource, {post_id: '17', association: 'author', source:'posts'} assert_response :success assert_hash_equals json_response, { diff --git a/test/fixtures/active_record.rb b/test/fixtures/active_record.rb index e1edb34cd..eb36bb766 100644 --- a/test/fixtures/active_record.rb +++ b/test/fixtures/active_record.rb @@ -96,7 +96,7 @@ t.string :spouse_name t.text :bio t.float :quality_rating - t.decimal :salary, :precision => 12, :scale => 2 + t.decimal :salary, precision: 12, scale: 2 t.datetime :date_time_joined t.date :birthday t.time :bedtime @@ -696,7 +696,7 @@ class BreedResource < JSONAPI::Resource attribute :name, format: :title # This is unneeded, just here for testing - routing_options :param => :id + routing_options param: :id def self.find(filters, options = {}) breeds = []