jsonapi-resources 0.5.4 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +9 -1
- data/lib/generators/jsonapi/USAGE +8 -0
- data/lib/generators/jsonapi/resource_generator.rb +14 -0
- data/lib/generators/jsonapi/templates/jsonapi_resource.rb +4 -0
- data/lib/jsonapi/configuration.rb +8 -3
- data/lib/jsonapi/exceptions.rb +2 -2
- data/lib/jsonapi/link_builder.rb +4 -2
- data/lib/jsonapi/operation.rb +31 -3
- data/lib/jsonapi/operation_result.rb +10 -0
- data/lib/jsonapi/paginator.rb +6 -2
- data/lib/jsonapi/request.rb +12 -0
- data/lib/jsonapi/resource.rb +3 -4
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/response_document.rb +21 -13
- data/test/controllers/controller_test.rb +32 -8
- data/test/integration/requests/request_test.rb +58 -0
- data/test/lib/generators/jsonapi/resource_generator_test.rb +25 -0
- data/test/unit/pagination/offset_paginator_test.rb +39 -0
- data/test/unit/pagination/paged_paginator_test.rb +39 -0
- data/test/unit/serializer/link_builder_test.rb +17 -0
- metadata +8 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: dcb37444c599cb514483e80217f64409d7745411
         | 
| 4 | 
            +
              data.tar.gz: eaeff3c3ee4183273ccb9cc59a1933781426c21f
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 829b54dedc77b56e63757c0ea593a98b562d573fc2f1ba221baa036f429e365b21c28f99c846c681d681677f7bca9c240ca617d133f39a1ea1c9292ecaf5b1d4
         | 
| 7 | 
            +
              data.tar.gz: dc68f574e96aa495ee6f6da7402869262864d169bdaa476b06948888935701f7601b2cdc9b0092c6a67bd9a89c1df96ae4c55c07a70a3f4223628d36a494588b
         | 
    
        data/README.md
    CHANGED
    
    | @@ -54,6 +54,11 @@ class ContactResource < JSONAPI::Resource | |
| 54 54 | 
             
            end
         | 
| 55 55 | 
             
            ```
         | 
| 56 56 |  | 
| 57 | 
            +
            A jsonapi-resource generator is avaliable
         | 
| 58 | 
            +
            ```
         | 
| 59 | 
            +
            rails generate jsonapi:resource contact 
         | 
| 60 | 
            +
            ```
         | 
| 61 | 
            +
             | 
| 57 62 | 
             
            ##### Abstract Resources
         | 
| 58 63 |  | 
| 59 64 | 
             
            Resources that are not backed by a model (purely used as base classes for other resources) should be declared as 
         | 
| @@ -1272,7 +1277,10 @@ JSONAPI.configure do |config| | |
| 1272 1277 | 
             
              #:basic, :active_record, or custom
         | 
| 1273 1278 | 
             
              config.operations_processor = :active_record
         | 
| 1274 1279 |  | 
| 1275 | 
            -
               | 
| 1280 | 
            +
              # optional request features
         | 
| 1281 | 
            +
              config.allow_include = true
         | 
| 1282 | 
            +
              config.allow_sort = true
         | 
| 1283 | 
            +
              config.allow_filter = true
         | 
| 1276 1284 |  | 
| 1277 1285 | 
             
              # :none, :offset, :paged, or a custom paginator name
         | 
| 1278 1286 | 
             
              config.default_paginator = :none
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            module Jsonapi
         | 
| 2 | 
            +
              class ResourceGenerator < Rails::Generators::NamedBase
         | 
| 3 | 
            +
                source_root File.expand_path('../templates', __FILE__)
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def create_resource
         | 
| 6 | 
            +
                  template_file = File.join(
         | 
| 7 | 
            +
                    'app/resources',
         | 
| 8 | 
            +
                    class_path,
         | 
| 9 | 
            +
                    "#{file_name}_resource.rb"
         | 
| 10 | 
            +
                  )
         | 
| 11 | 
            +
                  template 'jsonapi_resource.rb', template_file
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
| @@ -9,7 +9,9 @@ module JSONAPI | |
| 9 9 | 
             
                            :route_format,
         | 
| 10 10 | 
             
                            :route_formatter,
         | 
| 11 11 | 
             
                            :operations_processor,
         | 
| 12 | 
            -
                            : | 
| 12 | 
            +
                            :allow_include,
         | 
| 13 | 
            +
                            :allow_sort,
         | 
| 14 | 
            +
                            :allow_filter,
         | 
| 13 15 | 
             
                            :default_paginator,
         | 
| 14 16 | 
             
                            :default_page_size,
         | 
| 15 17 | 
             
                            :maximum_page_size,
         | 
| @@ -31,7 +33,10 @@ module JSONAPI | |
| 31 33 | 
             
                  #:basic, :active_record, or custom
         | 
| 32 34 | 
             
                  self.operations_processor = :active_record
         | 
| 33 35 |  | 
| 34 | 
            -
                   | 
| 36 | 
            +
                  # optional request features
         | 
| 37 | 
            +
                  self.allow_include = true
         | 
| 38 | 
            +
                  self.allow_sort = true
         | 
| 39 | 
            +
                  self.allow_filter = true
         | 
| 35 40 |  | 
| 36 41 | 
             
                  # :none, :offset, :paged, or a custom paginator name
         | 
| 37 42 | 
             
                  self.default_paginator = :none
         | 
| @@ -79,7 +84,7 @@ module JSONAPI | |
| 79 84 | 
             
                  @operations_processor = JSONAPI::OperationsProcessor.operations_processor_for(@operations_processor_name)
         | 
| 80 85 | 
             
                end
         | 
| 81 86 |  | 
| 82 | 
            -
                attr_writer : | 
| 87 | 
            +
                attr_writer :allow_include, :allow_sort, :allow_filter
         | 
| 83 88 |  | 
| 84 89 | 
             
                attr_writer :default_paginator
         | 
| 85 90 |  | 
    
        data/lib/jsonapi/exceptions.rb
    CHANGED
    
    | @@ -317,8 +317,8 @@ module JSONAPI | |
| 317 317 | 
             
                  def json_api_error(attr_key, message)
         | 
| 318 318 | 
             
                    JSONAPI::Error.new(code: JSONAPI::VALIDATION_ERROR,
         | 
| 319 319 | 
             
                                       status: :unprocessable_entity,
         | 
| 320 | 
            -
                                       title:  | 
| 321 | 
            -
                                       detail: message,
         | 
| 320 | 
            +
                                       title: message,
         | 
| 321 | 
            +
                                       detail: "#{format_key(attr_key)} - #{message}",
         | 
| 322 322 | 
             
                                       source: { pointer: pointer(attr_key) })
         | 
| 323 323 | 
             
                  end
         | 
| 324 324 |  | 
    
        data/lib/jsonapi/link_builder.rb
    CHANGED
    
    | @@ -31,8 +31,10 @@ module JSONAPI | |
| 31 31 | 
             
                  "#{ primary_resources_url }?#{ query_params.to_query }"
         | 
| 32 32 | 
             
                end
         | 
| 33 33 |  | 
| 34 | 
            -
                def relationships_related_link(source, relationship)
         | 
| 35 | 
            -
                  "#{ self_link(source) }/#{ route_for_relationship(relationship) }"
         | 
| 34 | 
            +
                def relationships_related_link(source, relationship, query_params = {})
         | 
| 35 | 
            +
                  url = "#{ self_link(source) }/#{ route_for_relationship(relationship) }"
         | 
| 36 | 
            +
                  url = "#{ url }?#{ query_params.to_query }" if query_params.present?
         | 
| 37 | 
            +
                  url
         | 
| 36 38 | 
             
                end
         | 
| 37 39 |  | 
| 38 40 | 
             
                def relationships_self_link(source, relationship)
         | 
    
        data/lib/jsonapi/operation.rb
    CHANGED
    
    | @@ -149,15 +149,43 @@ module JSONAPI | |
| 149 149 | 
             
                  @transactional = false
         | 
| 150 150 | 
             
                end
         | 
| 151 151 |  | 
| 152 | 
            -
                def  | 
| 153 | 
            -
                   | 
| 152 | 
            +
                def record_count
         | 
| 153 | 
            +
                  @_record_count ||= records.count
         | 
| 154 | 
            +
                end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                def source_resource
         | 
| 157 | 
            +
                  @_source_resource ||= @source_klass.find_by_key(@source_id, context: @context)
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                def records
         | 
| 161 | 
            +
                  related_resource_records = source_resource.records_for(@relationship_type)
         | 
| 162 | 
            +
                  @resource_klass.filter_records(@filters, @options, related_resource_records)
         | 
| 163 | 
            +
                end
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                def pagination_params
         | 
| 166 | 
            +
                  if @paginator && JSONAPI.configuration.top_level_links_include_pagination
         | 
| 167 | 
            +
                    options = {}
         | 
| 168 | 
            +
                    options[:record_count] = record_count if @paginator.class.requires_record_count
         | 
| 169 | 
            +
                    @paginator.links_page_params(options)
         | 
| 170 | 
            +
                  else
         | 
| 171 | 
            +
                    {}
         | 
| 172 | 
            +
                  end
         | 
| 173 | 
            +
                end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                def options
         | 
| 176 | 
            +
                  opts = {}
         | 
| 177 | 
            +
                  opts.merge!(pagination_params: pagination_params) if JSONAPI.configuration.top_level_links_include_pagination
         | 
| 178 | 
            +
                  opts.merge!(record_count: pagination_params) if JSONAPI.configuration.top_level_meta_include_record_count
         | 
| 179 | 
            +
                  opts
         | 
| 180 | 
            +
                end
         | 
| 154 181 |  | 
| 182 | 
            +
                def apply
         | 
| 155 183 | 
             
                  related_resource = source_resource.public_send(@relationship_type,
         | 
| 156 184 | 
             
                                                          filters:  @filters,
         | 
| 157 185 | 
             
                                                          sort_criteria: @sort_criteria,
         | 
| 158 186 | 
             
                                                          paginator: @paginator)
         | 
| 159 187 |  | 
| 160 | 
            -
                  return JSONAPI:: | 
| 188 | 
            +
                  return JSONAPI::RelatedResourcesOperationResult.new(:ok, source_resource, @relationship_type, related_resource, options)
         | 
| 161 189 |  | 
| 162 190 | 
             
                rescue JSONAPI::Exceptions::Error => e
         | 
| 163 191 | 
             
                  return JSONAPI::ErrorsOperationResult.new(e.errors[0].code, e.errors)
         | 
| @@ -42,6 +42,16 @@ module JSONAPI | |
| 42 42 | 
             
                end
         | 
| 43 43 | 
             
              end
         | 
| 44 44 |  | 
| 45 | 
            +
              class RelatedResourcesOperationResult < ResourcesOperationResult
         | 
| 46 | 
            +
                attr_accessor :source_resource, :_type
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def initialize(code, source_resource, type, resources, options = {})
         | 
| 49 | 
            +
                  @source_resource = source_resource
         | 
| 50 | 
            +
                  @_type = type
         | 
| 51 | 
            +
                  super(code, resources, options)
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
             | 
| 45 55 | 
             
              class LinksObjectOperationResult < OperationResult
         | 
| 46 56 | 
             
                attr_accessor :parent_resource, :relationship
         | 
| 47 57 |  | 
    
        data/lib/jsonapi/paginator.rb
    CHANGED
    
    | @@ -74,8 +74,12 @@ class OffsetPaginator < JSONAPI::Paginator | |
| 74 74 | 
             
                end
         | 
| 75 75 |  | 
| 76 76 | 
             
                if record_count
         | 
| 77 | 
            +
                  last_offset = record_count - @limit
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  last_offset = 0 if last_offset < 0
         | 
| 80 | 
            +
             | 
| 77 81 | 
             
                  links_page_params['last'] = {
         | 
| 78 | 
            -
                    'offset' =>  | 
| 82 | 
            +
                    'offset' => last_offset,
         | 
| 79 83 | 
             
                    'limit' => @limit
         | 
| 80 84 | 
             
                  }
         | 
| 81 85 | 
             
                end
         | 
| @@ -159,7 +163,7 @@ class PagedPaginator < JSONAPI::Paginator | |
| 159 163 |  | 
| 160 164 | 
             
                if record_count
         | 
| 161 165 | 
             
                  links_page_params['last'] = {
         | 
| 162 | 
            -
                    'number' => page_count,
         | 
| 166 | 
            +
                    'number' => page_count == 0 ? 1 : page_count,
         | 
| 163 167 | 
             
                    'size' => @size
         | 
| 164 168 | 
             
                  }
         | 
| 165 169 | 
             
                end
         | 
    
        data/lib/jsonapi/request.rb
    CHANGED
    
    | @@ -196,6 +196,10 @@ module JSONAPI | |
| 196 196 | 
             
                def parse_include_directives(include)
         | 
| 197 197 | 
             
                  return if include.nil?
         | 
| 198 198 |  | 
| 199 | 
            +
                  unless JSONAPI.configuration.allow_include
         | 
| 200 | 
            +
                    fail JSONAPI::Exceptions::ParametersNotAllowed.new([:include])
         | 
| 201 | 
            +
                  end
         | 
| 202 | 
            +
             | 
| 199 203 | 
             
                  included_resources = CSV.parse_line(include)
         | 
| 200 204 | 
             
                  return if included_resources.nil?
         | 
| 201 205 |  | 
| @@ -211,6 +215,10 @@ module JSONAPI | |
| 211 215 | 
             
                def parse_filters(filters)
         | 
| 212 216 | 
             
                  return unless filters
         | 
| 213 217 |  | 
| 218 | 
            +
                  unless JSONAPI.configuration.allow_filter
         | 
| 219 | 
            +
                    fail JSONAPI::Exceptions::ParametersNotAllowed.new([:filter])
         | 
| 220 | 
            +
                  end
         | 
| 221 | 
            +
             | 
| 214 222 | 
             
                  unless filters.class.method_defined?(:each)
         | 
| 215 223 | 
             
                    @errors.concat(JSONAPI::Exceptions::InvalidFiltersSyntax.new(filters).errors)
         | 
| 216 224 | 
             
                    return
         | 
| @@ -236,6 +244,10 @@ module JSONAPI | |
| 236 244 | 
             
                def parse_sort_criteria(sort_criteria)
         | 
| 237 245 | 
             
                  return unless sort_criteria.present?
         | 
| 238 246 |  | 
| 247 | 
            +
                  unless JSONAPI.configuration.allow_sort
         | 
| 248 | 
            +
                    fail JSONAPI::Exceptions::ParametersNotAllowed.new([:sort])
         | 
| 249 | 
            +
                  end
         | 
| 250 | 
            +
             | 
| 239 251 | 
             
                  @sort_criteria = CSV.parse_line(URI.unescape(sort_criteria)).collect do |sort|
         | 
| 240 252 | 
             
                    if sort.start_with?('-')
         | 
| 241 253 | 
             
                      sort_criteria = { field: unformat_key(sort[1..-1]).to_s }
         | 
    
        data/lib/jsonapi/resource.rb
    CHANGED
    
    | @@ -472,8 +472,7 @@ module JSONAPI | |
| 472 472 | 
             
                    records
         | 
| 473 473 | 
             
                  end
         | 
| 474 474 |  | 
| 475 | 
            -
                  def filter_records(filters, options)
         | 
| 476 | 
            -
                    records = records(options)
         | 
| 475 | 
            +
                  def filter_records(filters, options, records = records(options))
         | 
| 477 476 | 
             
                    records = apply_filters(records, filters, options)
         | 
| 478 477 | 
             
                    apply_includes(records, options)
         | 
| 479 478 | 
             
                  end
         | 
| @@ -483,7 +482,7 @@ module JSONAPI | |
| 483 482 | 
             
                  end
         | 
| 484 483 |  | 
| 485 484 | 
             
                  def find_count(filters, options = {})
         | 
| 486 | 
            -
                    filter_records(filters, options).count
         | 
| 485 | 
            +
                    filter_records(filters, options).count(:all)
         | 
| 487 486 | 
             
                  end
         | 
| 488 487 |  | 
| 489 488 | 
             
                  # Override this method if you have more complex requirements than this basic find method provides
         | 
| @@ -686,7 +685,7 @@ module JSONAPI | |
| 686 685 | 
             
                      check_reserved_relationship_name(attr)
         | 
| 687 686 |  | 
| 688 687 | 
             
                      # Initialize from an ActiveRecord model's properties
         | 
| 689 | 
            -
                      if _model_class && _model_class  | 
| 688 | 
            +
                      if _model_class && _model_class.ancestors.collect{|ancestor| ancestor.name}.include?('ActiveRecord::Base')
         | 
| 690 689 | 
             
                        model_association = _model_class.reflect_on_association(attr)
         | 
| 691 690 | 
             
                        if model_association
         | 
| 692 691 | 
             
                          options[:class_name] ||= model_association.class_name
         | 
| @@ -69,25 +69,33 @@ module JSONAPI | |
| 69 69 | 
             
                    links.merge!(result.links)
         | 
| 70 70 |  | 
| 71 71 | 
             
                    # Build pagination links
         | 
| 72 | 
            -
                    if result.is_a?(JSONAPI::ResourcesOperationResult)
         | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
                         | 
| 81 | 
            -
                        query_params[:filter] = request.params[:filter] if request.params[:filter]
         | 
| 82 | 
            -
             | 
| 83 | 
            -
                        links[link_name] = serializer.find_link(query_params)
         | 
| 84 | 
            -
                      end
         | 
| 72 | 
            +
                    if result.is_a?(JSONAPI::ResourcesOperationResult) || result.is_a?(JSONAPI::RelatedResourcesOperationResult)
         | 
| 73 | 
            +
                        result.pagination_params.each_pair do |link_name, params|
         | 
| 74 | 
            +
                          if result.is_a?(JSONAPI::RelatedResourcesOperationResult)
         | 
| 75 | 
            +
                            relationship = result.source_resource.class._relationships[result._type.to_sym]
         | 
| 76 | 
            +
                            links[link_name] = serializer.url_generator.relationships_related_link(result.source_resource, relationship, query_params(params))
         | 
| 77 | 
            +
                          else
         | 
| 78 | 
            +
                            links[link_name] = serializer.find_link(query_params(params))
         | 
| 79 | 
            +
                          end
         | 
| 80 | 
            +
                        end
         | 
| 85 81 | 
             
                    end
         | 
| 86 82 | 
             
                  end
         | 
| 87 83 |  | 
| 88 84 | 
             
                  links.deep_transform_keys { |key| @key_formatter.format(key) }
         | 
| 89 85 | 
             
                end
         | 
| 90 86 |  | 
| 87 | 
            +
                def query_params(params)
         | 
| 88 | 
            +
                  query_params = {}
         | 
| 89 | 
            +
                  query_params[:page] = params
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  request = @options[:request]
         | 
| 92 | 
            +
                  query_params[:fields] = request.params[:fields] if request.params[:fields]
         | 
| 93 | 
            +
                  query_params[:include] = request.params[:include] if request.params[:include]
         | 
| 94 | 
            +
                  query_params[:sort] = request.params[:sort] if request.params[:sort]
         | 
| 95 | 
            +
                  query_params[:filter] = request.params[:filter] if request.params[:filter]
         | 
| 96 | 
            +
                  query_params
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
             | 
| 91 99 | 
             
                def results_to_hash
         | 
| 92 100 | 
             
                  if @operation_results.has_errors?
         | 
| 93 101 | 
             
                    { errors: @operation_results.all_errors }
         | 
| @@ -69,6 +69,14 @@ class PostsControllerTest < ActionController::TestCase | |
| 69 69 | 
             
                assert_equal 1, json_response['included'].size
         | 
| 70 70 | 
             
              end
         | 
| 71 71 |  | 
| 72 | 
            +
              def test_index_filter_not_allowed
         | 
| 73 | 
            +
                JSONAPI.configuration.allow_filter = false
         | 
| 74 | 
            +
                get :index, {filter: {id: '1'}}
         | 
| 75 | 
            +
                assert_response :bad_request
         | 
| 76 | 
            +
              ensure
         | 
| 77 | 
            +
                JSONAPI.configuration.allow_filter = true
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
             | 
| 72 80 | 
             
              def test_index_include_one_level_query_count
         | 
| 73 81 | 
             
                count_queries do
         | 
| 74 82 | 
             
                  get :index, {include: 'author'}
         | 
| @@ -239,6 +247,14 @@ class PostsControllerTest < ActionController::TestCase | |
| 239 247 | 
             
                assert_match /asdfg is not a valid sort criteria for post/, response.body
         | 
| 240 248 | 
             
              end
         | 
| 241 249 |  | 
| 250 | 
            +
              def test_show_single_with_sort_disallowed
         | 
| 251 | 
            +
                JSONAPI.configuration.allow_sort = false
         | 
| 252 | 
            +
                get :index, {sort: 'title,body'}
         | 
| 253 | 
            +
                assert_response :bad_request
         | 
| 254 | 
            +
              ensure
         | 
| 255 | 
            +
                JSONAPI.configuration.allow_sort = true
         | 
| 256 | 
            +
              end
         | 
| 257 | 
            +
             | 
| 242 258 | 
             
              def test_excluded_sort_param
         | 
| 243 259 | 
             
                get :index, {sort: 'id'}
         | 
| 244 260 |  | 
| @@ -276,6 +292,14 @@ class PostsControllerTest < ActionController::TestCase | |
| 276 292 | 
             
                assert_equal 2, json_response['included'].size
         | 
| 277 293 | 
             
              end
         | 
| 278 294 |  | 
| 295 | 
            +
              def test_show_single_with_include_disallowed
         | 
| 296 | 
            +
                JSONAPI.configuration.allow_include = false
         | 
| 297 | 
            +
                get :show, {id: '1', include: 'comments'}
         | 
| 298 | 
            +
                assert_response :bad_request
         | 
| 299 | 
            +
              ensure
         | 
| 300 | 
            +
                JSONAPI.configuration.allow_include = true
         | 
| 301 | 
            +
              end
         | 
| 302 | 
            +
             | 
| 279 303 | 
             
              def test_show_single_with_fields
         | 
| 280 304 | 
             
                get :show, {id: '1', fields: {posts: 'author'}}
         | 
| 281 305 | 
             
                assert_response :success
         | 
| @@ -396,12 +420,12 @@ class PostsControllerTest < ActionController::TestCase | |
| 396 420 | 
             
                assert_response :unprocessable_entity
         | 
| 397 421 |  | 
| 398 422 | 
             
                assert_equal "/data/relationships/author", json_response['errors'][0]['source']['pointer']
         | 
| 399 | 
            -
                assert_equal "can't be blank", json_response['errors'][0][' | 
| 400 | 
            -
                assert_equal "author - can't be blank", json_response['errors'][0][' | 
| 423 | 
            +
                assert_equal "can't be blank", json_response['errors'][0]['title']
         | 
| 424 | 
            +
                assert_equal "author - can't be blank", json_response['errors'][0]['detail']
         | 
| 401 425 |  | 
| 402 426 | 
             
                assert_equal "/data/attributes/title", json_response['errors'][1]['source']['pointer']
         | 
| 403 | 
            -
                assert_equal "is too long (maximum is 35 characters)", json_response['errors'][1][' | 
| 404 | 
            -
                assert_equal "title - is too long (maximum is 35 characters)", json_response['errors'][1][' | 
| 427 | 
            +
                assert_equal "is too long (maximum is 35 characters)", json_response['errors'][1]['title']
         | 
| 428 | 
            +
                assert_equal "title - is too long (maximum is 35 characters)", json_response['errors'][1]['detail']
         | 
| 405 429 | 
             
              end
         | 
| 406 430 |  | 
| 407 431 | 
             
              def test_create_multiple
         | 
| @@ -2212,12 +2236,12 @@ class FactsControllerTest < ActionController::TestCase | |
| 2212 2236 | 
             
                assert_response :unprocessable_entity
         | 
| 2213 2237 |  | 
| 2214 2238 | 
             
                assert_equal "/data/attributes/spouse-name", json_response['errors'][0]['source']['pointer']
         | 
| 2215 | 
            -
                assert_equal "can't be blank", json_response['errors'][0][' | 
| 2216 | 
            -
                assert_equal "spouse-name - can't be blank", json_response['errors'][0][' | 
| 2239 | 
            +
                assert_equal "can't be blank", json_response['errors'][0]['title']
         | 
| 2240 | 
            +
                assert_equal "spouse-name - can't be blank", json_response['errors'][0]['detail']
         | 
| 2217 2241 |  | 
| 2218 2242 | 
             
                assert_equal "/data/attributes/bio", json_response['errors'][1]['source']['pointer']
         | 
| 2219 | 
            -
                assert_equal "can't be blank", json_response['errors'][1][' | 
| 2220 | 
            -
                assert_equal "bio - can't be blank", json_response['errors'][1][' | 
| 2243 | 
            +
                assert_equal "can't be blank", json_response['errors'][1]['title']
         | 
| 2244 | 
            +
                assert_equal "bio - can't be blank", json_response['errors'][1]['detail']
         | 
| 2221 2245 | 
             
              end
         | 
| 2222 2246 | 
             
            end
         | 
| 2223 2247 |  | 
| @@ -389,6 +389,25 @@ class RequestTest < ActionDispatch::IntegrationTest | |
| 389 389 | 
             
                assert_equal 'This is comment 18 on book 1.', json_response['data'][9]['attributes']['body']
         | 
| 390 390 | 
             
              end
         | 
| 391 391 |  | 
| 392 | 
            +
              def test_pagination_related_resources_links
         | 
| 393 | 
            +
                Api::V2::BookResource.paginator :offset
         | 
| 394 | 
            +
                Api::V2::BookCommentResource.paginator :offset
         | 
| 395 | 
            +
                get '/api/v2/books/1/book_comments?page[limit]=10'
         | 
| 396 | 
            +
                assert_equal 'http://www.example.com/api/v2/books/1/book_comments?page%5Blimit%5D=10&page%5Boffset%5D=0', json_response['links']['first']
         | 
| 397 | 
            +
                assert_equal 'http://www.example.com/api/v2/books/1/book_comments?page%5Blimit%5D=10&page%5Boffset%5D=10', json_response['links']['next']
         | 
| 398 | 
            +
                assert_equal 'http://www.example.com/api/v2/books/1/book_comments?page%5Blimit%5D=10&page%5Boffset%5D=41', json_response['links']['last']
         | 
| 399 | 
            +
              end
         | 
| 400 | 
            +
             | 
| 401 | 
            +
              def test_pagination_related_resources_without_related
         | 
| 402 | 
            +
                Api::V2::BookResource.paginator :offset
         | 
| 403 | 
            +
                Api::V2::BookCommentResource.paginator :offset
         | 
| 404 | 
            +
                get '/api/v2/books/10/book_comments'
         | 
| 405 | 
            +
                assert_equal 200, status
         | 
| 406 | 
            +
                assert_nil json_response['links']['next']
         | 
| 407 | 
            +
                assert_equal 'http://www.example.com/api/v2/books/10/book_comments?page%5Blimit%5D=10&page%5Boffset%5D=0', json_response['links']['first']
         | 
| 408 | 
            +
                assert_equal 'http://www.example.com/api/v2/books/10/book_comments?page%5Blimit%5D=10&page%5Boffset%5D=0', json_response['links']['last']
         | 
| 409 | 
            +
              end
         | 
| 410 | 
            +
             | 
| 392 411 | 
             
              def test_pagination_related_resources_data_includes
         | 
| 393 412 | 
             
                Api::V2::BookResource.paginator :offset
         | 
| 394 413 | 
             
                Api::V2::BookCommentResource.paginator :offset
         | 
| @@ -398,6 +417,17 @@ class RequestTest < ActionDispatch::IntegrationTest | |
| 398 417 | 
             
                assert_equal 'This is comment 18 on book 1.', json_response['data'][9]['attributes']['body']
         | 
| 399 418 | 
             
              end
         | 
| 400 419 |  | 
| 420 | 
            +
              def test_pagination_empty_results
         | 
| 421 | 
            +
                Api::V2::BookResource.paginator :offset
         | 
| 422 | 
            +
                Api::V2::BookCommentResource.paginator :offset
         | 
| 423 | 
            +
                get '/api/v2/books?filter[id]=2000&page[limit]=10'
         | 
| 424 | 
            +
                assert_equal 200, status
         | 
| 425 | 
            +
                assert_equal 0, json_response['data'].size
         | 
| 426 | 
            +
                assert_nil json_response['links']['next']
         | 
| 427 | 
            +
                assert_equal 'http://www.example.com/api/v2/books?filter%5Bid%5D=2000&page%5Blimit%5D=10&page%5Boffset%5D=0', json_response['links']['first']
         | 
| 428 | 
            +
                assert_equal 'http://www.example.com/api/v2/books?filter%5Bid%5D=2000&page%5Blimit%5D=10&page%5Boffset%5D=0', json_response['links']['last']
         | 
| 429 | 
            +
              end
         | 
| 430 | 
            +
             | 
| 401 431 | 
             
              # def test_pagination_related_resources_data_includes
         | 
| 402 432 | 
             
              #   Api::V2::BookResource.paginator :none
         | 
| 403 433 | 
             
              #   Api::V2::BookCommentResource.paginator :none
         | 
| @@ -691,4 +721,32 @@ class RequestTest < ActionDispatch::IntegrationTest | |
| 691 721 | 
             
                assert_equal 204, status
         | 
| 692 722 | 
             
              end
         | 
| 693 723 |  | 
| 724 | 
            +
              def test_include_parameter_allowed
         | 
| 725 | 
            +
                get '/api/v2/books/1/book_comments?include=author'
         | 
| 726 | 
            +
                assert_equal 200, status
         | 
| 727 | 
            +
              end
         | 
| 728 | 
            +
             | 
| 729 | 
            +
              def test_include_parameter_not_allowed
         | 
| 730 | 
            +
                JSONAPI.configuration.allow_include = false
         | 
| 731 | 
            +
                get '/api/v2/books/1/book_comments?include=author'
         | 
| 732 | 
            +
                assert_equal 400, status
         | 
| 733 | 
            +
              ensure
         | 
| 734 | 
            +
                JSONAPI.configuration.allow_include = true
         | 
| 735 | 
            +
              end
         | 
| 736 | 
            +
             | 
| 737 | 
            +
              def test_filter_parameter_not_allowed
         | 
| 738 | 
            +
                JSONAPI.configuration.allow_filter = false
         | 
| 739 | 
            +
                get '/api/v2/books?filter[author]=1'
         | 
| 740 | 
            +
                assert_equal 400, status
         | 
| 741 | 
            +
              ensure
         | 
| 742 | 
            +
                JSONAPI.configuration.allow_filter = true
         | 
| 743 | 
            +
              end
         | 
| 744 | 
            +
             | 
| 745 | 
            +
              def test_sort_parameter_not_allowed
         | 
| 746 | 
            +
                JSONAPI.configuration.allow_sort = false
         | 
| 747 | 
            +
                get '/api/v2/books?sort=title'
         | 
| 748 | 
            +
                assert_equal 400, status
         | 
| 749 | 
            +
              ensure
         | 
| 750 | 
            +
                JSONAPI.configuration.allow_sort = true
         | 
| 751 | 
            +
              end
         | 
| 694 752 | 
             
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
            require 'generators/jsonapi/resource_generator'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Jsonapi
         | 
| 5 | 
            +
              class ResourceGeneratorTest < Rails::Generators::TestCase
         | 
| 6 | 
            +
                tests ResourceGenerator
         | 
| 7 | 
            +
                destination Rails.root.join('../resources')
         | 
| 8 | 
            +
                setup :prepare_destination
         | 
| 9 | 
            +
                teardown :cleanup_destination_root
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def cleanup_destination_root
         | 
| 12 | 
            +
                  FileUtils.rm_rf destination_root
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                test "resource is created" do
         | 
| 16 | 
            +
                  run_generator ["post"]
         | 
| 17 | 
            +
                  assert_file 'app/resources/post_resource.rb', /class PostResource < JSONAPI::Resource/
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                test "resource is created with namespace" do
         | 
| 21 | 
            +
                  run_generator ["api/v1/post"]
         | 
| 22 | 
            +
                  assert_file 'app/resources/api/v1/post_resource.rb', /class Api::V1::PostResource < JSONAPI::Resource/
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -82,6 +82,45 @@ class OffsetPaginatorTest < ActiveSupport::TestCase | |
| 82 82 | 
             
                assert_equal 0, paginator.offset
         | 
| 83 83 | 
             
              end
         | 
| 84 84 |  | 
| 85 | 
            +
              def test_offset_links_page_params_empty_results
         | 
| 86 | 
            +
                params = ActionController::Parameters.new(
         | 
| 87 | 
            +
                  {
         | 
| 88 | 
            +
                    limit: 5,
         | 
| 89 | 
            +
                    offset: 0
         | 
| 90 | 
            +
                  }
         | 
| 91 | 
            +
                )
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                paginator = OffsetPaginator.new(params)
         | 
| 94 | 
            +
                links_params = paginator.links_page_params(record_count: 0)
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                assert_equal 2, links_params.size
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                assert_equal 5, links_params['first']['limit']
         | 
| 99 | 
            +
                assert_equal 0, links_params['first']['offset']
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                assert_equal 5, links_params['last']['limit']
         | 
| 102 | 
            +
                assert_equal 0, links_params['last']['offset']
         | 
| 103 | 
            +
              end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
              def test_offset_links_page_params_small_resultsets
         | 
| 106 | 
            +
                params = ActionController::Parameters.new(
         | 
| 107 | 
            +
                  {
         | 
| 108 | 
            +
                    limit: 5,
         | 
| 109 | 
            +
                    offset: 0
         | 
| 110 | 
            +
                  }
         | 
| 111 | 
            +
                )
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                paginator = OffsetPaginator.new(params)
         | 
| 114 | 
            +
                links_params = paginator.links_page_params(record_count: 3)
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                assert_equal 2, links_params.size
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                assert_equal 5, links_params['first']['limit']
         | 
| 119 | 
            +
                assert_equal 0, links_params['first']['offset']
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                assert_equal 5, links_params['last']['limit']
         | 
| 122 | 
            +
                assert_equal 0, links_params['last']['offset']
         | 
| 123 | 
            +
              end
         | 
| 85 124 |  | 
| 86 125 | 
             
              def test_offset_links_page_params_large_data_set_start
         | 
| 87 126 | 
             
                params = ActionController::Parameters.new(
         | 
| @@ -82,6 +82,45 @@ class PagedPaginatorTest < ActiveSupport::TestCase | |
| 82 82 | 
             
                assert_equal 1, paginator.number
         | 
| 83 83 | 
             
              end
         | 
| 84 84 |  | 
| 85 | 
            +
              def test_paged_links_page_params_empty_results
         | 
| 86 | 
            +
                params = ActionController::Parameters.new(
         | 
| 87 | 
            +
                  {
         | 
| 88 | 
            +
                    size: 5,
         | 
| 89 | 
            +
                    number: 1
         | 
| 90 | 
            +
                  }
         | 
| 91 | 
            +
                )
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                paginator = PagedPaginator.new(params)
         | 
| 94 | 
            +
                links_params = paginator.links_page_params(record_count: 0)
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                assert_equal 2, links_params.size
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                assert_equal 5, links_params['first']['size']
         | 
| 99 | 
            +
                assert_equal 1, links_params['first']['number']
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                assert_equal 5, links_params['last']['size']
         | 
| 102 | 
            +
                assert_equal 1, links_params['last']['number']
         | 
| 103 | 
            +
              end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
              def test_paged_links_page_params_small_resultsets
         | 
| 106 | 
            +
                params = ActionController::Parameters.new(
         | 
| 107 | 
            +
                  {
         | 
| 108 | 
            +
                    size: 5,
         | 
| 109 | 
            +
                    number: 1
         | 
| 110 | 
            +
                  }
         | 
| 111 | 
            +
                )
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                paginator = PagedPaginator.new(params)
         | 
| 114 | 
            +
                links_params = paginator.links_page_params(record_count: 3)
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                assert_equal 2, links_params.size
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                assert_equal 5, links_params['first']['size']
         | 
| 119 | 
            +
                assert_equal 1, links_params['first']['number']
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                assert_equal 5, links_params['last']['size']
         | 
| 122 | 
            +
                assert_equal 1, links_params['last']['number']
         | 
| 123 | 
            +
              end
         | 
| 85 124 |  | 
| 86 125 | 
             
              def test_paged_links_page_params_large_data_set_start_full_pages
         | 
| 87 126 | 
             
                params = ActionController::Parameters.new(
         | 
| @@ -169,6 +169,23 @@ class LinkBuilderTest < ActionDispatch::IntegrationTest | |
| 169 169 | 
             
                  builder.relationships_related_link(source, relationship)
         | 
| 170 170 | 
             
              end
         | 
| 171 171 |  | 
| 172 | 
            +
              def test_relationships_related_link_with_query_params
         | 
| 173 | 
            +
                config = {
         | 
| 174 | 
            +
                  base_url: @base_url,
         | 
| 175 | 
            +
                  route_formatter: @route_formatter,
         | 
| 176 | 
            +
                  primary_resource_klass: Api::V1::PersonResource
         | 
| 177 | 
            +
                }
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                builder       = JSONAPI::LinkBuilder.new(config)
         | 
| 180 | 
            +
                source        = Api::V1::PersonResource.new(@steve)
         | 
| 181 | 
            +
                relationship  = JSONAPI::Relationship::ToMany.new("posts", {})
         | 
| 182 | 
            +
                expected_link = "#{ @base_url }/api/v1/people/#{ @steve.id }/posts?page%5Blimit%5D=12&page%5Boffset%5D=0"
         | 
| 183 | 
            +
                query         = { page: { offset: 0, limit: 12 } }
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                assert_equal expected_link,
         | 
| 186 | 
            +
                             builder.relationships_related_link(source, relationship, query)
         | 
| 187 | 
            +
              end
         | 
| 188 | 
            +
             | 
| 172 189 | 
             
              def test_query_link_for_regular_app
         | 
| 173 190 | 
             
                config = {
         | 
| 174 191 | 
             
                  base_url: @base_url,
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: jsonapi-resources
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.5. | 
| 4 | 
            +
              version: 0.5.5
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Dan Gebhardt
         | 
| @@ -9,7 +9,7 @@ authors: | |
| 9 9 | 
             
            autorequire: 
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date: 2015- | 
| 12 | 
            +
            date: 2015-08-10 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: bundler
         | 
| @@ -139,6 +139,9 @@ files: | |
| 139 139 | 
             
            - README.md
         | 
| 140 140 | 
             
            - Rakefile
         | 
| 141 141 | 
             
            - jsonapi-resources.gemspec
         | 
| 142 | 
            +
            - lib/generators/jsonapi/USAGE
         | 
| 143 | 
            +
            - lib/generators/jsonapi/resource_generator.rb
         | 
| 144 | 
            +
            - lib/generators/jsonapi/templates/jsonapi_resource.rb
         | 
| 142 145 | 
             
            - lib/jsonapi-resources.rb
         | 
| 143 146 | 
             
            - lib/jsonapi/active_record_operations_processor.rb
         | 
| 144 147 | 
             
            - lib/jsonapi/acts_as_resource_controller.rb
         | 
| @@ -202,6 +205,7 @@ files: | |
| 202 205 | 
             
            - test/helpers/value_matchers_test.rb
         | 
| 203 206 | 
             
            - test/integration/requests/request_test.rb
         | 
| 204 207 | 
             
            - test/integration/routes/routes_test.rb
         | 
| 208 | 
            +
            - test/lib/generators/jsonapi/resource_generator_test.rb
         | 
| 205 209 | 
             
            - test/test_helper.rb
         | 
| 206 210 | 
             
            - test/unit/jsonapi_request/jsonapi_request_test.rb
         | 
| 207 211 | 
             
            - test/unit/operation/operations_processor_test.rb
         | 
| @@ -276,6 +280,7 @@ test_files: | |
| 276 280 | 
             
            - test/helpers/value_matchers_test.rb
         | 
| 277 281 | 
             
            - test/integration/requests/request_test.rb
         | 
| 278 282 | 
             
            - test/integration/routes/routes_test.rb
         | 
| 283 | 
            +
            - test/lib/generators/jsonapi/resource_generator_test.rb
         | 
| 279 284 | 
             
            - test/test_helper.rb
         | 
| 280 285 | 
             
            - test/unit/jsonapi_request/jsonapi_request_test.rb
         | 
| 281 286 | 
             
            - test/unit/operation/operations_processor_test.rb
         | 
| @@ -287,3 +292,4 @@ test_files: | |
| 287 292 | 
             
            - test/unit/serializer/polymorphic_serializer_test.rb
         | 
| 288 293 | 
             
            - test/unit/serializer/response_document_test.rb
         | 
| 289 294 | 
             
            - test/unit/serializer/serializer_test.rb
         | 
| 295 | 
            +
            has_rdoc: 
         |