jsonapi-resources 0.7.1.beta1 → 0.7.1.beta2
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 +248 -74
 - data/lib/jsonapi-resources.rb +5 -3
 - data/lib/jsonapi/acts_as_resource_controller.rb +77 -14
 - data/lib/jsonapi/configuration.rb +77 -16
 - data/lib/jsonapi/error.rb +12 -0
 - data/lib/jsonapi/error_codes.rb +2 -0
 - data/lib/jsonapi/exceptions.rb +29 -9
 - data/lib/jsonapi/formatter.rb +29 -4
 - data/lib/jsonapi/link_builder.rb +18 -18
 - data/lib/jsonapi/mime_types.rb +25 -6
 - data/lib/jsonapi/naive_cache.rb +30 -0
 - data/lib/jsonapi/operation.rb +10 -342
 - data/lib/jsonapi/operation_dispatcher.rb +87 -0
 - data/lib/jsonapi/operation_result.rb +2 -1
 - data/lib/jsonapi/paginator.rb +6 -2
 - data/lib/jsonapi/processor.rb +283 -0
 - data/lib/jsonapi/relationship.rb +6 -4
 - data/lib/jsonapi/{request.rb → request_parser.rb} +46 -35
 - data/lib/jsonapi/resource.rb +88 -13
 - data/lib/jsonapi/resource_controller.rb +2 -14
 - data/lib/jsonapi/resource_controller_metal.rb +17 -0
 - data/lib/jsonapi/resource_serializer.rb +62 -47
 - data/lib/jsonapi/resources/version.rb +1 -1
 - data/lib/jsonapi/response_document.rb +13 -2
 - data/lib/jsonapi/routing_ext.rb +49 -11
 - metadata +37 -129
 - data/.gitignore +0 -22
 - data/.travis.yml +0 -9
 - data/Gemfile +0 -23
 - data/Rakefile +0 -20
 - data/jsonapi-resources.gemspec +0 -29
 - data/lib/jsonapi/active_record_operations_processor.rb +0 -35
 - data/lib/jsonapi/operations_processor.rb +0 -120
 - data/locales/en.yml +0 -80
 - data/test/config/database.yml +0 -5
 - data/test/controllers/controller_test.rb +0 -3312
 - data/test/fixtures/active_record.rb +0 -1486
 - data/test/fixtures/author_details.yml +0 -9
 - data/test/fixtures/book_authors.yml +0 -3
 - data/test/fixtures/book_comments.yml +0 -12
 - data/test/fixtures/books.yml +0 -7
 - data/test/fixtures/categories.yml +0 -35
 - data/test/fixtures/comments.yml +0 -21
 - data/test/fixtures/comments_tags.yml +0 -20
 - data/test/fixtures/companies.yml +0 -4
 - data/test/fixtures/craters.yml +0 -9
 - data/test/fixtures/customers.yml +0 -11
 - data/test/fixtures/documents.yml +0 -3
 - data/test/fixtures/expense_entries.yml +0 -13
 - data/test/fixtures/facts.yml +0 -11
 - data/test/fixtures/hair_cuts.yml +0 -3
 - data/test/fixtures/iso_currencies.yml +0 -17
 - data/test/fixtures/line_items.yml +0 -37
 - data/test/fixtures/makes.yml +0 -2
 - data/test/fixtures/moons.yml +0 -6
 - data/test/fixtures/numeros_telefone.yml +0 -3
 - data/test/fixtures/order_flags.yml +0 -7
 - data/test/fixtures/people.yml +0 -31
 - data/test/fixtures/pictures.yml +0 -15
 - data/test/fixtures/planet_types.yml +0 -19
 - data/test/fixtures/planets.yml +0 -47
 - data/test/fixtures/posts.yml +0 -102
 - data/test/fixtures/posts_tags.yml +0 -59
 - data/test/fixtures/preferences.yml +0 -14
 - data/test/fixtures/products.yml +0 -3
 - data/test/fixtures/purchase_orders.yml +0 -23
 - data/test/fixtures/sections.yml +0 -8
 - data/test/fixtures/tags.yml +0 -39
 - data/test/fixtures/vehicles.yml +0 -17
 - data/test/fixtures/web_pages.yml +0 -3
 - data/test/helpers/assertions.rb +0 -13
 - data/test/helpers/functional_helpers.rb +0 -59
 - data/test/helpers/value_matchers.rb +0 -60
 - data/test/helpers/value_matchers_test.rb +0 -40
 - data/test/integration/requests/namespaced_model_test.rb +0 -13
 - data/test/integration/requests/request_test.rb +0 -932
 - data/test/integration/routes/routes_test.rb +0 -218
 - data/test/integration/sti_fields_test.rb +0 -18
 - data/test/lib/generators/jsonapi/controller_generator_test.rb +0 -25
 - data/test/lib/generators/jsonapi/resource_generator_test.rb +0 -30
 - data/test/test_helper.rb +0 -342
 - data/test/unit/formatters/dasherized_key_formatter_test.rb +0 -8
 - data/test/unit/jsonapi_request/jsonapi_request_test.rb +0 -199
 - data/test/unit/operation/operations_processor_test.rb +0 -528
 - data/test/unit/pagination/offset_paginator_test.rb +0 -245
 - data/test/unit/pagination/paged_paginator_test.rb +0 -242
 - data/test/unit/resource/resource_test.rb +0 -560
 - data/test/unit/serializer/include_directives_test.rb +0 -113
 - data/test/unit/serializer/link_builder_test.rb +0 -244
 - data/test/unit/serializer/polymorphic_serializer_test.rb +0 -383
 - data/test/unit/serializer/response_document_test.rb +0 -61
 - data/test/unit/serializer/serializer_test.rb +0 -1939
 
| 
         @@ -2,7 +2,7 @@ require 'jsonapi/operation' 
     | 
|
| 
       2 
2 
     | 
    
         
             
            require 'jsonapi/paginator'
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
4 
     | 
    
         
             
            module JSONAPI
         
     | 
| 
       5 
     | 
    
         
            -
              class  
     | 
| 
      
 5 
     | 
    
         
            +
              class RequestParser
         
     | 
| 
       6 
6 
     | 
    
         
             
                attr_accessor :fields, :include, :filters, :sort_criteria, :errors, :operations,
         
     | 
| 
       7 
7 
     | 
    
         
             
                              :resource_klass, :context, :paginator, :source_klass, :source_id,
         
     | 
| 
       8 
8 
     | 
    
         
             
                              :include_directives, :params, :warnings, :server_error_callbacks
         
     | 
| 
         @@ -289,27 +289,29 @@ module JSONAPI 
     | 
|
| 
       289 
289 
     | 
    
         
             
                end
         
     | 
| 
       290 
290 
     | 
    
         | 
| 
       291 
291 
     | 
    
         
             
                def add_find_operation
         
     | 
| 
       292 
     | 
    
         
            -
                  @operations.push JSONAPI:: 
     | 
| 
      
 292 
     | 
    
         
            +
                  @operations.push JSONAPI::Operation.new(:find,
         
     | 
| 
       293 
293 
     | 
    
         
             
                    @resource_klass,
         
     | 
| 
       294 
294 
     | 
    
         
             
                    context: @context,
         
     | 
| 
       295 
295 
     | 
    
         
             
                    filters: @filters,
         
     | 
| 
       296 
296 
     | 
    
         
             
                    include_directives: @include_directives,
         
     | 
| 
       297 
297 
     | 
    
         
             
                    sort_criteria: @sort_criteria,
         
     | 
| 
       298 
     | 
    
         
            -
                    paginator: @paginator
         
     | 
| 
      
 298 
     | 
    
         
            +
                    paginator: @paginator,
         
     | 
| 
      
 299 
     | 
    
         
            +
                    fields: @fields
         
     | 
| 
       299 
300 
     | 
    
         
             
                  )
         
     | 
| 
       300 
301 
     | 
    
         
             
                end
         
     | 
| 
       301 
302 
     | 
    
         | 
| 
       302 
303 
     | 
    
         
             
                def add_show_operation
         
     | 
| 
       303 
     | 
    
         
            -
                  @operations.push JSONAPI:: 
     | 
| 
      
 304 
     | 
    
         
            +
                  @operations.push JSONAPI::Operation.new(:show,
         
     | 
| 
       304 
305 
     | 
    
         
             
                    @resource_klass,
         
     | 
| 
       305 
306 
     | 
    
         
             
                    context: @context,
         
     | 
| 
       306 
307 
     | 
    
         
             
                    id: @id,
         
     | 
| 
       307 
     | 
    
         
            -
                    include_directives: @include_directives
         
     | 
| 
      
 308 
     | 
    
         
            +
                    include_directives: @include_directives,
         
     | 
| 
      
 309 
     | 
    
         
            +
                    fields: @fields
         
     | 
| 
       308 
310 
     | 
    
         
             
                  )
         
     | 
| 
       309 
311 
     | 
    
         
             
                end
         
     | 
| 
       310 
312 
     | 
    
         | 
| 
       311 
313 
     | 
    
         
             
                def add_show_relationship_operation(relationship_type, parent_key)
         
     | 
| 
       312 
     | 
    
         
            -
                  @operations.push JSONAPI:: 
     | 
| 
      
 314 
     | 
    
         
            +
                  @operations.push JSONAPI::Operation.new(:show_relationship,
         
     | 
| 
       313 
315 
     | 
    
         
             
                    @resource_klass,
         
     | 
| 
       314 
316 
     | 
    
         
             
                    context: @context,
         
     | 
| 
       315 
317 
     | 
    
         
             
                    relationship_type: relationship_type,
         
     | 
| 
         @@ -318,17 +320,18 @@ module JSONAPI 
     | 
|
| 
       318 
320 
     | 
    
         
             
                end
         
     | 
| 
       319 
321 
     | 
    
         | 
| 
       320 
322 
     | 
    
         
             
                def add_show_related_resource_operation(relationship_type)
         
     | 
| 
       321 
     | 
    
         
            -
                  @operations.push JSONAPI:: 
     | 
| 
      
 323 
     | 
    
         
            +
                  @operations.push JSONAPI::Operation.new(:show_related_resource,
         
     | 
| 
       322 
324 
     | 
    
         
             
                    @resource_klass,
         
     | 
| 
       323 
325 
     | 
    
         
             
                    context: @context,
         
     | 
| 
       324 
326 
     | 
    
         
             
                    relationship_type: relationship_type,
         
     | 
| 
       325 
327 
     | 
    
         
             
                    source_klass: @source_klass,
         
     | 
| 
       326 
     | 
    
         
            -
                    source_id: @source_id
         
     | 
| 
      
 328 
     | 
    
         
            +
                    source_id: @source_id,
         
     | 
| 
      
 329 
     | 
    
         
            +
                    fields: @fields
         
     | 
| 
       327 
330 
     | 
    
         
             
                  )
         
     | 
| 
       328 
331 
     | 
    
         
             
                end
         
     | 
| 
       329 
332 
     | 
    
         | 
| 
       330 
333 
     | 
    
         
             
                def add_show_related_resources_operation(relationship_type)
         
     | 
| 
       331 
     | 
    
         
            -
                  @operations.push JSONAPI:: 
     | 
| 
      
 334 
     | 
    
         
            +
                  @operations.push JSONAPI::Operation.new(:show_related_resources,
         
     | 
| 
       332 
335 
     | 
    
         
             
                    @resource_klass,
         
     | 
| 
       333 
336 
     | 
    
         
             
                    context: @context,
         
     | 
| 
       334 
337 
     | 
    
         
             
                    relationship_type: relationship_type,
         
     | 
| 
         @@ -336,7 +339,8 @@ module JSONAPI 
     | 
|
| 
       336 
339 
     | 
    
         
             
                    source_id: @source_id,
         
     | 
| 
       337 
340 
     | 
    
         
             
                    filters: @source_klass.verify_filters(@filters, @context),
         
     | 
| 
       338 
341 
     | 
    
         
             
                    sort_criteria: @sort_criteria,
         
     | 
| 
       339 
     | 
    
         
            -
                    paginator: @paginator
         
     | 
| 
      
 342 
     | 
    
         
            +
                    paginator: @paginator,
         
     | 
| 
      
 343 
     | 
    
         
            +
                    fields: @fields
         
     | 
| 
       340 
344 
     | 
    
         
             
                  )
         
     | 
| 
       341 
345 
     | 
    
         
             
                end
         
     | 
| 
       342 
346 
     | 
    
         | 
| 
         @@ -356,10 +360,11 @@ module JSONAPI 
     | 
|
| 
       356 
360 
     | 
    
         
             
                    verify_type(params[:type])
         
     | 
| 
       357 
361 
     | 
    
         | 
| 
       358 
362 
     | 
    
         
             
                    data = parse_params(params, creatable_fields)
         
     | 
| 
       359 
     | 
    
         
            -
                    @operations.push JSONAPI:: 
     | 
| 
      
 363 
     | 
    
         
            +
                    @operations.push JSONAPI::Operation.new(:create_resource,
         
     | 
| 
       360 
364 
     | 
    
         
             
                      @resource_klass,
         
     | 
| 
       361 
365 
     | 
    
         
             
                      context: @context,
         
     | 
| 
       362 
     | 
    
         
            -
                      data: data
         
     | 
| 
      
 366 
     | 
    
         
            +
                      data: data,
         
     | 
| 
      
 367 
     | 
    
         
            +
                      fields: @fields
         
     | 
| 
       363 
368 
     | 
    
         
             
                    )
         
     | 
| 
       364 
369 
     | 
    
         
             
                  end
         
     | 
| 
       365 
370 
     | 
    
         
             
                rescue JSONAPI::Exceptions::Error => e
         
     | 
| 
         @@ -382,7 +387,8 @@ module JSONAPI 
     | 
|
| 
       382 
387 
     | 
    
         
             
                    }
         
     | 
| 
       383 
388 
     | 
    
         
             
                  end
         
     | 
| 
       384 
389 
     | 
    
         | 
| 
       385 
     | 
    
         
            -
                  if !raw.is_a?(Hash) || raw. 
     | 
| 
      
 390 
     | 
    
         
            +
                  if !(raw.is_a?(Hash) || raw.is_a?(ActionController::Parameters)) ||
         
     | 
| 
      
 391 
     | 
    
         
            +
                     raw.keys.length != 2 || !(raw.key?('type') && raw.key?('id'))
         
     | 
| 
       386 
392 
     | 
    
         
             
                    fail JSONAPI::Exceptions::InvalidLinksObject.new
         
     | 
| 
       387 
393 
     | 
    
         
             
                  end
         
     | 
| 
       388 
394 
     | 
    
         | 
| 
         @@ -476,7 +482,7 @@ module JSONAPI 
     | 
|
| 
       476 
482 
     | 
    
         
             
                def parse_to_many_relationship(link_value, relationship, &add_result)
         
     | 
| 
       477 
483 
     | 
    
         
             
                  if link_value.is_a?(Array) && link_value.length == 0
         
     | 
| 
       478 
484 
     | 
    
         
             
                    linkage = []
         
     | 
| 
       479 
     | 
    
         
            -
                  elsif link_value.is_a?(Hash)
         
     | 
| 
      
 485 
     | 
    
         
            +
                  elsif (link_value.is_a?(Hash) || link_value.is_a?(ActionController::Parameters))
         
     | 
| 
       480 
486 
     | 
    
         
             
                    linkage = link_value[:data]
         
     | 
| 
       481 
487 
     | 
    
         
             
                  else
         
     | 
| 
       482 
488 
     | 
    
         
             
                    fail JSONAPI::Exceptions::InvalidLinksObject.new
         
     | 
| 
         @@ -531,7 +537,14 @@ module JSONAPI 
     | 
|
| 
       531 
537 
     | 
    
         
             
                          end
         
     | 
| 
       532 
538 
     | 
    
         
             
                        end
         
     | 
| 
       533 
539 
     | 
    
         
             
                      end
         
     | 
| 
       534 
     | 
    
         
            -
                    when 'type' 
     | 
| 
      
 540 
     | 
    
         
            +
                    when 'type'
         
     | 
| 
      
 541 
     | 
    
         
            +
                    when 'id'
         
     | 
| 
      
 542 
     | 
    
         
            +
                      unless formatted_allowed_fields.include?(:id)
         
     | 
| 
      
 543 
     | 
    
         
            +
                        params_not_allowed.push(:id)
         
     | 
| 
      
 544 
     | 
    
         
            +
                        unless JSONAPI.configuration.raise_if_parameters_not_allowed
         
     | 
| 
      
 545 
     | 
    
         
            +
                          params.delete :id
         
     | 
| 
      
 546 
     | 
    
         
            +
                        end
         
     | 
| 
      
 547 
     | 
    
         
            +
                      end
         
     | 
| 
       535 
548 
     | 
    
         
             
                    else
         
     | 
| 
       536 
549 
     | 
    
         
             
                      params_not_allowed.push(key)
         
     | 
| 
       537 
550 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -564,7 +577,7 @@ module JSONAPI 
     | 
|
| 
       564 
577 
     | 
    
         | 
| 
       565 
578 
     | 
    
         
             
                def parse_add_relationship_operation(verified_params, relationship, parent_key)
         
     | 
| 
       566 
579 
     | 
    
         
             
                  if relationship.is_a?(JSONAPI::Relationship::ToMany)
         
     | 
| 
       567 
     | 
    
         
            -
                    @operations.push JSONAPI:: 
     | 
| 
      
 580 
     | 
    
         
            +
                    @operations.push JSONAPI::Operation.new(:create_to_many_relationship,
         
     | 
| 
       568 
581 
     | 
    
         
             
                      resource_klass,
         
     | 
| 
       569 
582 
     | 
    
         
             
                      context: @context,
         
     | 
| 
       570 
583 
     | 
    
         
             
                      resource_id: parent_key,
         
     | 
| 
         @@ -575,40 +588,37 @@ module JSONAPI 
     | 
|
| 
       575 
588 
     | 
    
         
             
                end
         
     | 
| 
       576 
589 
     | 
    
         | 
| 
       577 
590 
     | 
    
         
             
                def parse_update_relationship_operation(verified_params, relationship, parent_key)
         
     | 
| 
       578 
     | 
    
         
            -
                   
     | 
| 
      
 591 
     | 
    
         
            +
                  options = {
         
     | 
| 
       579 
592 
     | 
    
         
             
                    context: @context,
         
     | 
| 
       580 
593 
     | 
    
         
             
                    resource_id: parent_key,
         
     | 
| 
       581 
594 
     | 
    
         
             
                    relationship_type: relationship.name
         
     | 
| 
       582 
     | 
    
         
            -
                   
     | 
| 
      
 595 
     | 
    
         
            +
                  }
         
     | 
| 
       583 
596 
     | 
    
         | 
| 
       584 
597 
     | 
    
         
             
                  if relationship.is_a?(JSONAPI::Relationship::ToOne)
         
     | 
| 
       585 
598 
     | 
    
         
             
                    if relationship.polymorphic?
         
     | 
| 
       586 
     | 
    
         
            -
                       
     | 
| 
       587 
     | 
    
         
            -
             
     | 
| 
       588 
     | 
    
         
            -
                        key_type: verified_params[:to_one].values[0][:type]
         
     | 
| 
       589 
     | 
    
         
            -
                      )
         
     | 
| 
      
 599 
     | 
    
         
            +
                      options[:key_value] = verified_params[:to_one].values[0][:id]
         
     | 
| 
      
 600 
     | 
    
         
            +
                      options[:key_type] = verified_params[:to_one].values[0][:type]
         
     | 
| 
       590 
601 
     | 
    
         | 
| 
       591 
     | 
    
         
            -
                       
     | 
| 
      
 602 
     | 
    
         
            +
                      operation_type = :replace_polymorphic_to_one_relationship
         
     | 
| 
       592 
603 
     | 
    
         
             
                    else
         
     | 
| 
       593 
     | 
    
         
            -
                       
     | 
| 
       594 
     | 
    
         
            -
                       
     | 
| 
      
 604 
     | 
    
         
            +
                      options[:key_value] = verified_params[:to_one].values[0]
         
     | 
| 
      
 605 
     | 
    
         
            +
                      operation_type = :replace_to_one_relationship
         
     | 
| 
       595 
606 
     | 
    
         
             
                    end
         
     | 
| 
       596 
607 
     | 
    
         
             
                  elsif relationship.is_a?(JSONAPI::Relationship::ToMany)
         
     | 
| 
       597 
608 
     | 
    
         
             
                    unless relationship.acts_as_set
         
     | 
| 
       598 
609 
     | 
    
         
             
                      fail JSONAPI::Exceptions::ToManySetReplacementForbidden.new
         
     | 
| 
       599 
610 
     | 
    
         
             
                    end
         
     | 
| 
       600 
     | 
    
         
            -
             
     | 
| 
       601 
     | 
    
         
            -
                     
     | 
| 
       602 
     | 
    
         
            -
                    operation_klass = JSONAPI::ReplaceToManyRelationshipOperation
         
     | 
| 
      
 611 
     | 
    
         
            +
                    options[:data] = verified_params[:to_many].values[0]
         
     | 
| 
      
 612 
     | 
    
         
            +
                    operation_type = :replace_to_many_relationship
         
     | 
| 
       603 
613 
     | 
    
         
             
                  end
         
     | 
| 
       604 
614 
     | 
    
         | 
| 
       605 
     | 
    
         
            -
                  @operations.push 
     | 
| 
      
 615 
     | 
    
         
            +
                  @operations.push JSONAPI::Operation.new(operation_type, resource_klass, options)
         
     | 
| 
       606 
616 
     | 
    
         
             
                end
         
     | 
| 
       607 
617 
     | 
    
         | 
| 
       608 
618 
     | 
    
         
             
                def parse_single_replace_operation(data, keys, id_key_presence_check_required: true)
         
     | 
| 
       609 
619 
     | 
    
         
             
                  fail JSONAPI::Exceptions::MissingKey.new if data[:id].nil?
         
     | 
| 
       610 
620 
     | 
    
         | 
| 
       611 
     | 
    
         
            -
                  key = data[:id]
         
     | 
| 
      
 621 
     | 
    
         
            +
                  key = data[:id].to_s
         
     | 
| 
       612 
622 
     | 
    
         
             
                  if id_key_presence_check_required && !keys.include?(key)
         
     | 
| 
       613 
623 
     | 
    
         
             
                    fail JSONAPI::Exceptions::KeyNotIncludedInURL.new(key)
         
     | 
| 
       614 
624 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -617,11 +627,12 @@ module JSONAPI 
     | 
|
| 
       617 
627 
     | 
    
         | 
| 
       618 
628 
     | 
    
         
             
                  verify_type(data[:type])
         
     | 
| 
       619 
629 
     | 
    
         | 
| 
       620 
     | 
    
         
            -
                  @operations.push JSONAPI:: 
     | 
| 
      
 630 
     | 
    
         
            +
                  @operations.push JSONAPI::Operation.new(:replace_fields,
         
     | 
| 
       621 
631 
     | 
    
         
             
                    @resource_klass,
         
     | 
| 
       622 
632 
     | 
    
         
             
                    context: @context,
         
     | 
| 
       623 
633 
     | 
    
         
             
                    resource_id: key,
         
     | 
| 
       624 
     | 
    
         
            -
                    data: parse_params(data, updatable_fields)
         
     | 
| 
      
 634 
     | 
    
         
            +
                    data: parse_params(data, updatable_fields),
         
     | 
| 
      
 635 
     | 
    
         
            +
                    fields: @fields
         
     | 
| 
       625 
636 
     | 
    
         
             
                  )
         
     | 
| 
       626 
637 
     | 
    
         
             
                end
         
     | 
| 
       627 
638 
     | 
    
         | 
| 
         @@ -645,7 +656,7 @@ module JSONAPI 
     | 
|
| 
       645 
656 
     | 
    
         
             
                  keys = parse_key_array(params.require(:id))
         
     | 
| 
       646 
657 
     | 
    
         | 
| 
       647 
658 
     | 
    
         
             
                  keys.each do |key|
         
     | 
| 
       648 
     | 
    
         
            -
                    @operations.push JSONAPI:: 
     | 
| 
      
 659 
     | 
    
         
            +
                    @operations.push JSONAPI::Operation.new(:remove_resource,
         
     | 
| 
       649 
660 
     | 
    
         
             
                      @resource_klass,
         
     | 
| 
       650 
661 
     | 
    
         
             
                      context: @context,
         
     | 
| 
       651 
662 
     | 
    
         
             
                      resource_id: key
         
     | 
| 
         @@ -667,12 +678,12 @@ module JSONAPI 
     | 
|
| 
       667 
678 
     | 
    
         
             
                    keys.each do |key|
         
     | 
| 
       668 
679 
     | 
    
         
             
                      operation_args = operation_base_args.dup
         
     | 
| 
       669 
680 
     | 
    
         
             
                      operation_args[1] = operation_args[1].merge(associated_key: key)
         
     | 
| 
       670 
     | 
    
         
            -
                      @operations.push JSONAPI:: 
     | 
| 
      
 681 
     | 
    
         
            +
                      @operations.push JSONAPI::Operation.new(:remove_to_many_relationship,
         
     | 
| 
       671 
682 
     | 
    
         
             
                        *operation_args
         
     | 
| 
       672 
683 
     | 
    
         
             
                      )
         
     | 
| 
       673 
684 
     | 
    
         
             
                    end
         
     | 
| 
       674 
685 
     | 
    
         
             
                  else
         
     | 
| 
       675 
     | 
    
         
            -
                    @operations.push JSONAPI:: 
     | 
| 
      
 686 
     | 
    
         
            +
                    @operations.push JSONAPI::Operation.new(:remove_to_one_relationship,
         
     | 
| 
       676 
687 
     | 
    
         
             
                      *operation_base_args
         
     | 
| 
       677 
688 
     | 
    
         
             
                    )
         
     | 
| 
       678 
689 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/jsonapi/resource.rb
    CHANGED
    
    | 
         @@ -152,6 +152,15 @@ module JSONAPI 
     | 
|
| 
       152 
152 
     | 
    
         
             
                  {}
         
     | 
| 
       153 
153 
     | 
    
         
             
                end
         
     | 
| 
       154 
154 
     | 
    
         | 
| 
      
 155 
     | 
    
         
            +
                # Override this to return custom links
         
     | 
| 
      
 156 
     | 
    
         
            +
                # must return a hash, which will be merged with the default { self: 'self-url' } links hash
         
     | 
| 
      
 157 
     | 
    
         
            +
                # links keys will be not be formatted with the key formatter for the serializer by default.
         
     | 
| 
      
 158 
     | 
    
         
            +
                # They can however use the serializer's format_key and format_value methods if desired
         
     | 
| 
      
 159 
     | 
    
         
            +
                # the _options hash will contain the serializer and the serialization_options
         
     | 
| 
      
 160 
     | 
    
         
            +
                def custom_links(_options)
         
     | 
| 
      
 161 
     | 
    
         
            +
                  {}
         
     | 
| 
      
 162 
     | 
    
         
            +
                end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
       155 
164 
     | 
    
         
             
                private
         
     | 
| 
       156 
165 
     | 
    
         | 
| 
       157 
166 
     | 
    
         
             
                def save
         
     | 
| 
         @@ -173,8 +182,8 @@ module JSONAPI 
     | 
|
| 
       173 
182 
     | 
    
         
             
                #   return :accepted
         
     | 
| 
       174 
183 
     | 
    
         
             
                # end
         
     | 
| 
       175 
184 
     | 
    
         
             
                # ```
         
     | 
| 
       176 
     | 
    
         
            -
                def _save
         
     | 
| 
       177 
     | 
    
         
            -
                  unless @model.valid?
         
     | 
| 
      
 185 
     | 
    
         
            +
                def _save(validation_context = nil)
         
     | 
| 
      
 186 
     | 
    
         
            +
                  unless @model.valid?(validation_context)
         
     | 
| 
       178 
187 
     | 
    
         
             
                    fail JSONAPI::Exceptions::ValidationErrors.new(self)
         
     | 
| 
       179 
188 
     | 
    
         
             
                  end
         
     | 
| 
       180 
189 
     | 
    
         | 
| 
         @@ -201,6 +210,9 @@ module JSONAPI 
     | 
|
| 
       201 
210 
     | 
    
         
             
                    fail JSONAPI::Exceptions::ValidationErrors.new(self)
         
     | 
| 
       202 
211 
     | 
    
         
             
                  end
         
     | 
| 
       203 
212 
     | 
    
         
             
                  :completed
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
                rescue ActiveRecord::DeleteRestrictionError => e
         
     | 
| 
      
 215 
     | 
    
         
            +
                  fail JSONAPI::Exceptions::RecordLocked.new(e.message)
         
     | 
| 
       204 
216 
     | 
    
         
             
                end
         
     | 
| 
       205 
217 
     | 
    
         | 
| 
       206 
218 
     | 
    
         
             
                def _create_to_many_links(relationship_type, relationship_key_values)
         
     | 
| 
         @@ -256,6 +268,11 @@ module JSONAPI 
     | 
|
| 
       256 
268 
     | 
    
         
             
                  @model.public_send(relation_name).delete(key)
         
     | 
| 
       257 
269 
     | 
    
         | 
| 
       258 
270 
     | 
    
         
             
                  :completed
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
                rescue ActiveRecord::DeleteRestrictionError => e
         
     | 
| 
      
 273 
     | 
    
         
            +
                  fail JSONAPI::Exceptions::RecordLocked.new(e.message)
         
     | 
| 
      
 274 
     | 
    
         
            +
                rescue ActiveRecord::RecordNotFound
         
     | 
| 
      
 275 
     | 
    
         
            +
                  fail JSONAPI::Exceptions::RecordNotFound.new(key)
         
     | 
| 
       259 
276 
     | 
    
         
             
                end
         
     | 
| 
       260 
277 
     | 
    
         | 
| 
       261 
278 
     | 
    
         
             
                def _remove_to_one_link(relationship_type)
         
     | 
| 
         @@ -390,11 +407,11 @@ module JSONAPI 
     | 
|
| 
       390 
407 
     | 
    
         
             
                    @_attributes ||= {}
         
     | 
| 
       391 
408 
     | 
    
         
             
                    @_attributes[attr] = options
         
     | 
| 
       392 
409 
     | 
    
         
             
                    define_method attr do
         
     | 
| 
       393 
     | 
    
         
            -
                      @model.public_send(attr)
         
     | 
| 
      
 410 
     | 
    
         
            +
                      @model.public_send(options[:delegate] ? options[:delegate].to_sym : attr)
         
     | 
| 
       394 
411 
     | 
    
         
             
                    end unless method_defined?(attr)
         
     | 
| 
       395 
412 
     | 
    
         | 
| 
       396 
413 
     | 
    
         
             
                    define_method "#{attr}=" do |value|
         
     | 
| 
       397 
     | 
    
         
            -
                      @model.public_send 
     | 
| 
      
 414 
     | 
    
         
            +
                      @model.public_send("#{options[:delegate] ? options[:delegate].to_sym : attr}=", value)
         
     | 
| 
       398 
415 
     | 
    
         
             
                    end unless method_defined?("#{attr}=")
         
     | 
| 
       399 
416 
     | 
    
         
             
                  end
         
     | 
| 
       400 
417 
     | 
    
         | 
| 
         @@ -521,17 +538,57 @@ module JSONAPI 
     | 
|
| 
       521 
538 
     | 
    
         | 
| 
       522 
539 
     | 
    
         
             
                  def apply_sort(records, order_options, _context = {})
         
     | 
| 
       523 
540 
     | 
    
         
             
                    if order_options.any?
         
     | 
| 
       524 
     | 
    
         
            -
             
     | 
| 
       525 
     | 
    
         
            -
             
     | 
| 
       526 
     | 
    
         
            -
             
     | 
| 
      
 541 
     | 
    
         
            +
                       order_options.each_pair do |field, direction|
         
     | 
| 
      
 542 
     | 
    
         
            +
                        if field.to_s.include?(".")
         
     | 
| 
      
 543 
     | 
    
         
            +
                          *model_names, column_name = field.split(".")
         
     | 
| 
      
 544 
     | 
    
         
            +
             
     | 
| 
      
 545 
     | 
    
         
            +
                          associations = _lookup_association_chain([records.model.to_s, *model_names])
         
     | 
| 
      
 546 
     | 
    
         
            +
                          joins_query = _build_joins([records.model, *associations])
         
     | 
| 
      
 547 
     | 
    
         
            +
             
     | 
| 
      
 548 
     | 
    
         
            +
                          # _sorting is appended to avoid name clashes with manual joins eg. overriden filters
         
     | 
| 
      
 549 
     | 
    
         
            +
                          order_by_query = "#{associations.last.name}_sorting.#{column_name} #{direction}"
         
     | 
| 
      
 550 
     | 
    
         
            +
                          records = records.joins(joins_query).order(order_by_query)
         
     | 
| 
      
 551 
     | 
    
         
            +
                        else
         
     | 
| 
      
 552 
     | 
    
         
            +
                          records = records.order(field => direction)
         
     | 
| 
      
 553 
     | 
    
         
            +
                        end
         
     | 
| 
      
 554 
     | 
    
         
            +
                      end
         
     | 
| 
      
 555 
     | 
    
         
            +
                    end
         
     | 
| 
      
 556 
     | 
    
         
            +
             
     | 
| 
      
 557 
     | 
    
         
            +
                    records
         
     | 
| 
      
 558 
     | 
    
         
            +
                  end
         
     | 
| 
      
 559 
     | 
    
         
            +
             
     | 
| 
      
 560 
     | 
    
         
            +
                  def _lookup_association_chain(model_names)
         
     | 
| 
      
 561 
     | 
    
         
            +
                    associations = []
         
     | 
| 
      
 562 
     | 
    
         
            +
                    model_names.inject do |prev, current|
         
     | 
| 
      
 563 
     | 
    
         
            +
                      association = prev.classify.constantize.reflect_on_all_associations.detect do |assoc|
         
     | 
| 
      
 564 
     | 
    
         
            +
                        assoc.name.to_s.downcase == current.downcase
         
     | 
| 
      
 565 
     | 
    
         
            +
                      end
         
     | 
| 
      
 566 
     | 
    
         
            +
                      associations << association
         
     | 
| 
      
 567 
     | 
    
         
            +
                      association.class_name
         
     | 
| 
      
 568 
     | 
    
         
            +
                    end
         
     | 
| 
      
 569 
     | 
    
         
            +
             
     | 
| 
      
 570 
     | 
    
         
            +
                    associations
         
     | 
| 
      
 571 
     | 
    
         
            +
                  end
         
     | 
| 
      
 572 
     | 
    
         
            +
             
     | 
| 
      
 573 
     | 
    
         
            +
                  def _build_joins(associations)
         
     | 
| 
      
 574 
     | 
    
         
            +
                    joins = []
         
     | 
| 
      
 575 
     | 
    
         
            +
             
     | 
| 
      
 576 
     | 
    
         
            +
                    associations.inject do |prev, current|
         
     | 
| 
      
 577 
     | 
    
         
            +
                      joins << "LEFT JOIN #{current.table_name} AS #{current.name}_sorting ON #{current.name}_sorting.id = #{prev.table_name}.#{current.foreign_key}"
         
     | 
| 
      
 578 
     | 
    
         
            +
                      current
         
     | 
| 
       527 
579 
     | 
    
         
             
                    end
         
     | 
| 
      
 580 
     | 
    
         
            +
                    joins.join("\n")
         
     | 
| 
       528 
581 
     | 
    
         
             
                  end
         
     | 
| 
       529 
582 
     | 
    
         | 
| 
       530 
583 
     | 
    
         
             
                  def apply_filter(records, filter, value, options = {})
         
     | 
| 
       531 
584 
     | 
    
         
             
                    strategy = _allowed_filters.fetch(filter.to_sym, Hash.new)[:apply]
         
     | 
| 
       532 
585 
     | 
    
         | 
| 
       533 
586 
     | 
    
         
             
                    if strategy
         
     | 
| 
       534 
     | 
    
         
            -
                      strategy. 
     | 
| 
      
 587 
     | 
    
         
            +
                      if strategy.is_a?(Symbol) || strategy.is_a?(String)
         
     | 
| 
      
 588 
     | 
    
         
            +
                        send(strategy, records, value, options)
         
     | 
| 
      
 589 
     | 
    
         
            +
                      else
         
     | 
| 
      
 590 
     | 
    
         
            +
                        strategy.call(records, value, options)
         
     | 
| 
      
 591 
     | 
    
         
            +
                      end
         
     | 
| 
       535 
592 
     | 
    
         
             
                    else
         
     | 
| 
       536 
593 
     | 
    
         
             
                      records.where(filter => value)
         
     | 
| 
       537 
594 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -571,8 +628,13 @@ module JSONAPI 
     | 
|
| 
       571 
628 
     | 
    
         
             
                    apply_sort(records, order_options, context)
         
     | 
| 
       572 
629 
     | 
    
         
             
                  end
         
     | 
| 
       573 
630 
     | 
    
         | 
| 
      
 631 
     | 
    
         
            +
                  # Assumes ActiveRecord's counting. Override if you need a different counting method
         
     | 
| 
      
 632 
     | 
    
         
            +
                  def count_records(records)
         
     | 
| 
      
 633 
     | 
    
         
            +
                    records.count(:all)
         
     | 
| 
      
 634 
     | 
    
         
            +
                  end
         
     | 
| 
      
 635 
     | 
    
         
            +
             
     | 
| 
       574 
636 
     | 
    
         
             
                  def find_count(filters, options = {})
         
     | 
| 
       575 
     | 
    
         
            -
                    filter_records(filters, options) 
     | 
| 
      
 637 
     | 
    
         
            +
                    count_records(filter_records(filters, options))
         
     | 
| 
       576 
638 
     | 
    
         
             
                  end
         
     | 
| 
       577 
639 
     | 
    
         | 
| 
       578 
640 
     | 
    
         
             
                  # Override this method if you have more complex requirements than this basic find method provides
         
     | 
| 
         @@ -587,9 +649,15 @@ module JSONAPI 
     | 
|
| 
       587 
649 
     | 
    
         | 
| 
       588 
650 
     | 
    
         
             
                    records = apply_pagination(records, options[:paginator], order_options)
         
     | 
| 
       589 
651 
     | 
    
         | 
| 
      
 652 
     | 
    
         
            +
                    resources_for(records, context)
         
     | 
| 
      
 653 
     | 
    
         
            +
                  end
         
     | 
| 
      
 654 
     | 
    
         
            +
             
     | 
| 
      
 655 
     | 
    
         
            +
                  def resources_for(records, context)
         
     | 
| 
       590 
656 
     | 
    
         
             
                    resources = []
         
     | 
| 
      
 657 
     | 
    
         
            +
                    resource_classes = {}
         
     | 
| 
       591 
658 
     | 
    
         
             
                    records.each do |model|
         
     | 
| 
       592 
     | 
    
         
            -
                       
     | 
| 
      
 659 
     | 
    
         
            +
                      resource_class = resource_classes[model.class] ||= self.resource_for_model(model)
         
     | 
| 
      
 660 
     | 
    
         
            +
                      resources.push resource_class.new(model, context)
         
     | 
| 
       593 
661 
     | 
    
         
             
                    end
         
     | 
| 
       594 
662 
     | 
    
         | 
| 
       595 
663 
     | 
    
         
             
                    resources
         
     | 
| 
         @@ -625,12 +693,19 @@ module JSONAPI 
     | 
|
| 
       625 
693 
     | 
    
         | 
| 
       626 
694 
     | 
    
         
             
                  def verify_filter(filter, raw, context = nil)
         
     | 
| 
       627 
695 
     | 
    
         
             
                    filter_values = []
         
     | 
| 
       628 
     | 
    
         
            -
                     
     | 
| 
      
 696 
     | 
    
         
            +
                    if raw.present?
         
     | 
| 
      
 697 
     | 
    
         
            +
                      filter_values += raw.is_a?(String) ? CSV.parse_line(raw) : [raw]
         
     | 
| 
      
 698 
     | 
    
         
            +
                    end
         
     | 
| 
       629 
699 
     | 
    
         | 
| 
       630 
700 
     | 
    
         
             
                    strategy = _allowed_filters.fetch(filter, Hash.new)[:verify]
         
     | 
| 
       631 
701 
     | 
    
         | 
| 
       632 
702 
     | 
    
         
             
                    if strategy
         
     | 
| 
       633 
     | 
    
         
            -
                       
     | 
| 
      
 703 
     | 
    
         
            +
                      if strategy.is_a?(Symbol) || strategy.is_a?(String)
         
     | 
| 
      
 704 
     | 
    
         
            +
                        values = send(strategy, filter_values, context)
         
     | 
| 
      
 705 
     | 
    
         
            +
                      else
         
     | 
| 
      
 706 
     | 
    
         
            +
                        values = strategy.call(filter_values, context)
         
     | 
| 
      
 707 
     | 
    
         
            +
                      end
         
     | 
| 
      
 708 
     | 
    
         
            +
                      [filter, values]
         
     | 
| 
       634 
709 
     | 
    
         
             
                    else
         
     | 
| 
       635 
710 
     | 
    
         
             
                      if is_filter_relationship?(filter)
         
     | 
| 
       636 
711 
     | 
    
         
             
                        verify_relationship_filter(filter, filter_values, context)
         
     | 
| 
         @@ -645,7 +720,7 @@ module JSONAPI 
     | 
|
| 
       645 
720 
     | 
    
         
             
                  end
         
     | 
| 
       646 
721 
     | 
    
         | 
| 
       647 
722 
     | 
    
         
             
                  def resource_key_type
         
     | 
| 
       648 
     | 
    
         
            -
                    @_resource_key_type  
     | 
| 
      
 723 
     | 
    
         
            +
                    @_resource_key_type ||= JSONAPI.configuration.resource_key_type
         
     | 
| 
       649 
724 
     | 
    
         
             
                  end
         
     | 
| 
       650 
725 
     | 
    
         | 
| 
       651 
726 
     | 
    
         
             
                  def verify_key(key, context = nil)
         
     | 
| 
         @@ -1,17 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module JSONAPI
         
     | 
| 
       2 
     | 
    
         
            -
              class ResourceController < ActionController:: 
     | 
| 
       3 
     | 
    
         
            -
                 
     | 
| 
       4 
     | 
    
         
            -
                  AbstractController::Rendering,
         
     | 
| 
       5 
     | 
    
         
            -
                  ActionController::Rendering,
         
     | 
| 
       6 
     | 
    
         
            -
                  ActionController::Renderers::All,
         
     | 
| 
       7 
     | 
    
         
            -
                  ActionController::StrongParameters,
         
     | 
| 
       8 
     | 
    
         
            -
                  ActionController::ForceSSL,
         
     | 
| 
       9 
     | 
    
         
            -
                  ActionController::Instrumentation,
         
     | 
| 
       10 
     | 
    
         
            -
                  JSONAPI::ActsAsResourceController
         
     | 
| 
       11 
     | 
    
         
            -
                ].freeze
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                MODULES.each do |mod|
         
     | 
| 
       14 
     | 
    
         
            -
                  include mod
         
     | 
| 
       15 
     | 
    
         
            -
                end
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ResourceController < ActionController::Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                include JSONAPI::ActsAsResourceController
         
     | 
| 
       16 
4 
     | 
    
         
             
              end
         
     | 
| 
       17 
5 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module JSONAPI
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ResourceControllerMetal < ActionController::Metal
         
     | 
| 
      
 3 
     | 
    
         
            +
                MODULES = [
         
     | 
| 
      
 4 
     | 
    
         
            +
                  AbstractController::Rendering,
         
     | 
| 
      
 5 
     | 
    
         
            +
                  ActionController::Rendering,
         
     | 
| 
      
 6 
     | 
    
         
            +
                  ActionController::Renderers::All,
         
     | 
| 
      
 7 
     | 
    
         
            +
                  ActionController::StrongParameters,
         
     | 
| 
      
 8 
     | 
    
         
            +
                  ActionController::ForceSSL,
         
     | 
| 
      
 9 
     | 
    
         
            +
                  ActionController::Instrumentation,
         
     | 
| 
      
 10 
     | 
    
         
            +
                  JSONAPI::ActsAsResourceController
         
     | 
| 
      
 11 
     | 
    
         
            +
                ].freeze
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                MODULES.each do |mod|
         
     | 
| 
      
 14 
     | 
    
         
            +
                  include mod
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -12,7 +12,7 @@ module JSONAPI 
     | 
|
| 
       12 
12 
     | 
    
         
             
                #     Purpose: determines which fields are serialized for a resource type. This encompasses both attributes and
         
     | 
| 
       13 
13 
     | 
    
         
             
                #              relationship ids in the links section for a resource. Fields are global for a resource type.
         
     | 
| 
       14 
14 
     | 
    
         
             
                #     Example: { people: [:id, :email, :comments], posts: [:id, :title, :author], comments: [:id, :body, :post]}
         
     | 
| 
       15 
     | 
    
         
            -
                # key_formatter: KeyFormatter  
     | 
| 
      
 15 
     | 
    
         
            +
                # key_formatter: KeyFormatter instance to override the default configuration
         
     | 
| 
       16 
16 
     | 
    
         
             
                # serializer_options: additional options that will be passed to resource meta and links lambdas
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                def initialize(primary_resource_klass, options = {})
         
     | 
| 
         @@ -21,16 +21,23 @@ module JSONAPI 
     | 
|
| 
       21 
21 
     | 
    
         
             
                  @include            = options.fetch(:include, [])
         
     | 
| 
       22 
22 
     | 
    
         
             
                  @include_directives = options[:include_directives]
         
     | 
| 
       23 
23 
     | 
    
         
             
                  @key_formatter      = options.fetch(:key_formatter, JSONAPI.configuration.key_formatter)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @id_formatter       = ValueFormatter.value_formatter_for(:id)
         
     | 
| 
       24 
25 
     | 
    
         
             
                  @link_builder       = generate_link_builder(primary_resource_klass, options)
         
     | 
| 
       25 
26 
     | 
    
         
             
                  @always_include_to_one_linkage_data = options.fetch(:always_include_to_one_linkage_data,
         
     | 
| 
       26 
27 
     | 
    
         
             
                                                                      JSONAPI.configuration.always_include_to_one_linkage_data)
         
     | 
| 
       27 
28 
     | 
    
         
             
                  @always_include_to_many_linkage_data = options.fetch(:always_include_to_many_linkage_data,
         
     | 
| 
       28 
29 
     | 
    
         
             
                                                                       JSONAPI.configuration.always_include_to_many_linkage_data)
         
     | 
| 
       29 
30 
     | 
    
         
             
                  @serialization_options = options.fetch(:serialization_options, {})
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  # Warning: This makes ResourceSerializer non-thread-safe. That's not a problem with the
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # request-specific way it's currently used, though.
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @value_formatter_type_cache = NaiveCache.new{|arg| ValueFormatter.value_formatter_for(arg) }
         
     | 
| 
       30 
35 
     | 
    
         
             
                end
         
     | 
| 
       31 
36 
     | 
    
         | 
| 
       32 
37 
     | 
    
         
             
                # Converts a single resource, or an array of resources to a hash, conforming to the JSONAPI structure
         
     | 
| 
       33 
38 
     | 
    
         
             
                def serialize_to_hash(source)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @top_level_sources = Set.new([source].flatten.compact.map {|s| top_level_source_key(s) })
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
       34 
41 
     | 
    
         
             
                  is_resource_collection = source.respond_to?(:to_ary)
         
     | 
| 
       35 
42 
     | 
    
         | 
| 
       36 
43 
     | 
    
         
             
                  @included_objects = {}
         
     | 
| 
         @@ -81,8 +88,7 @@ module JSONAPI 
     | 
|
| 
       81 
88 
     | 
    
         
             
                end
         
     | 
| 
       82 
89 
     | 
    
         | 
| 
       83 
90 
     | 
    
         
             
                def format_value(value, format)
         
     | 
| 
       84 
     | 
    
         
            -
                   
     | 
| 
       85 
     | 
    
         
            -
                  value_formatter.format(value)
         
     | 
| 
      
 91 
     | 
    
         
            +
                  @value_formatter_type_cache.get(format).format(value)
         
     | 
| 
       86 
92 
     | 
    
         
             
                end
         
     | 
| 
       87 
93 
     | 
    
         | 
| 
       88 
94 
     | 
    
         
             
                private
         
     | 
| 
         @@ -114,19 +120,18 @@ module JSONAPI 
     | 
|
| 
       114 
120 
     | 
    
         | 
| 
       115 
121 
     | 
    
         
             
                  obj_hash['type'] = format_key(source.class._type.to_s)
         
     | 
| 
       116 
122 
     | 
    
         | 
| 
       117 
     | 
    
         
            -
                  links =  
     | 
| 
      
 123 
     | 
    
         
            +
                  links = links_hash(source)
         
     | 
| 
       118 
124 
     | 
    
         
             
                  obj_hash['links'] = links unless links.empty?
         
     | 
| 
       119 
125 
     | 
    
         | 
| 
       120 
     | 
    
         
            -
                  attributes =  
     | 
| 
      
 126 
     | 
    
         
            +
                  attributes = attributes_hash(source)
         
     | 
| 
       121 
127 
     | 
    
         
             
                  obj_hash['attributes'] = attributes unless attributes.empty?
         
     | 
| 
       122 
128 
     | 
    
         | 
| 
       123 
     | 
    
         
            -
                  relationships =  
     | 
| 
      
 129 
     | 
    
         
            +
                  relationships = relationships_hash(source, include_directives)
         
     | 
| 
       124 
130 
     | 
    
         
             
                  obj_hash['relationships'] = relationships unless relationships.nil? || relationships.empty?
         
     | 
| 
       125 
131 
     | 
    
         | 
| 
       126 
     | 
    
         
            -
                  meta = source 
     | 
| 
       127 
     | 
    
         
            -
                   
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
                  end
         
     | 
| 
      
 132 
     | 
    
         
            +
                  meta = meta_hash(source)
         
     | 
| 
      
 133 
     | 
    
         
            +
                  obj_hash['meta'] = meta unless meta.empty?
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
       130 
135 
     | 
    
         
             
                  obj_hash
         
     | 
| 
       131 
136 
     | 
    
         
             
                end
         
     | 
| 
       132 
137 
     | 
    
         | 
| 
         @@ -139,7 +144,7 @@ module JSONAPI 
     | 
|
| 
       139 
144 
     | 
    
         
             
                  end
         
     | 
| 
       140 
145 
     | 
    
         
             
                end
         
     | 
| 
       141 
146 
     | 
    
         | 
| 
       142 
     | 
    
         
            -
                def  
     | 
| 
      
 147 
     | 
    
         
            +
                def attributes_hash(source)
         
     | 
| 
       143 
148 
     | 
    
         
             
                  requested = requested_fields(source.class)
         
     | 
| 
       144 
149 
     | 
    
         
             
                  fields = source.fetchable_fields & source.class._attributes.keys.to_a
         
     | 
| 
       145 
150 
     | 
    
         
             
                  fields = requested & fields unless requested.nil?
         
     | 
| 
         @@ -159,7 +164,31 @@ module JSONAPI 
     | 
|
| 
       159 
164 
     | 
    
         
             
                  }
         
     | 
| 
       160 
165 
     | 
    
         
             
                end
         
     | 
| 
       161 
166 
     | 
    
         | 
| 
       162 
     | 
    
         
            -
                def  
     | 
| 
      
 167 
     | 
    
         
            +
                def meta_hash(source)
         
     | 
| 
      
 168 
     | 
    
         
            +
                  meta = source.meta(custom_generation_options)
         
     | 
| 
      
 169 
     | 
    
         
            +
                  (meta.is_a?(Hash) && meta) || {}
         
     | 
| 
      
 170 
     | 
    
         
            +
                end
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                def links_hash(source)
         
     | 
| 
      
 173 
     | 
    
         
            +
                  {
         
     | 
| 
      
 174 
     | 
    
         
            +
                    self: link_builder.self_link(source)
         
     | 
| 
      
 175 
     | 
    
         
            +
                  }.merge(custom_links_hash(source)).compact
         
     | 
| 
      
 176 
     | 
    
         
            +
                end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                def custom_links_hash(source)
         
     | 
| 
      
 179 
     | 
    
         
            +
                  custom_links = source.custom_links(custom_generation_options)
         
     | 
| 
      
 180 
     | 
    
         
            +
                  (custom_links.is_a?(Hash) && custom_links) || {}
         
     | 
| 
      
 181 
     | 
    
         
            +
                end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                def top_level_source_key(source)
         
     | 
| 
      
 184 
     | 
    
         
            +
                  "#{source.class}_#{source.id}"
         
     | 
| 
      
 185 
     | 
    
         
            +
                end
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
                def self_referential_and_already_in_source(resource)
         
     | 
| 
      
 188 
     | 
    
         
            +
                  resource && @top_level_sources.include?(top_level_source_key(resource))
         
     | 
| 
      
 189 
     | 
    
         
            +
                end
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
                def relationships_hash(source, include_directives)
         
     | 
| 
       163 
192 
     | 
    
         
             
                  relationships = source.class._relationships
         
     | 
| 
       164 
193 
     | 
    
         
             
                  requested = requested_fields(source.class)
         
     | 
| 
       165 
194 
     | 
    
         
             
                  fields = relationships.keys
         
     | 
| 
         @@ -177,39 +206,24 @@ module JSONAPI 
     | 
|
| 
       177 
206 
     | 
    
         | 
| 
       178 
207 
     | 
    
         
             
                      include_linkage = ia && ia[:include]
         
     | 
| 
       179 
208 
     | 
    
         
             
                      include_linked_children = ia && !ia[:include_related].empty?
         
     | 
| 
      
 209 
     | 
    
         
            +
                      resources = (include_linkage || include_linked_children) && [source.public_send(name)].flatten.compact
         
     | 
| 
       180 
210 
     | 
    
         | 
| 
       181 
211 
     | 
    
         
             
                      if field_set.include?(name)
         
     | 
| 
       182 
212 
     | 
    
         
             
                        hash[format_key(name)] = link_object(source, relationship, include_linkage)
         
     | 
| 
       183 
213 
     | 
    
         
             
                      end
         
     | 
| 
       184 
214 
     | 
    
         | 
| 
       185 
     | 
    
         
            -
                      type = relationship.type
         
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
215 
     | 
    
         
             
                      # If the object has been serialized once it will be in the related objects list,
         
     | 
| 
       188 
216 
     | 
    
         
             
                      # but it's possible all children won't have been captured. So we must still go
         
     | 
| 
       189 
217 
     | 
    
         
             
                      # through the relationships.
         
     | 
| 
       190 
218 
     | 
    
         
             
                      if include_linkage || include_linked_children
         
     | 
| 
       191 
     | 
    
         
            -
                         
     | 
| 
       192 
     | 
    
         
            -
                           
     | 
| 
       193 
     | 
    
         
            -
                           
     | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
       195 
     | 
    
         
            -
             
     | 
| 
       196 
     | 
    
         
            -
                             
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
       198 
     | 
    
         
            -
             
     | 
| 
       199 
     | 
    
         
            -
                            elsif include_linked_children || relationships_only
         
     | 
| 
       200 
     | 
    
         
            -
                              relationship_data(resource, ia)
         
     | 
| 
       201 
     | 
    
         
            -
                            end
         
     | 
| 
       202 
     | 
    
         
            -
                          end
         
     | 
| 
       203 
     | 
    
         
            -
                        elsif relationship.is_a?(JSONAPI::Relationship::ToMany)
         
     | 
| 
       204 
     | 
    
         
            -
                          resources = source.public_send(name)
         
     | 
| 
       205 
     | 
    
         
            -
                          resources.each do |resource|
         
     | 
| 
       206 
     | 
    
         
            -
                            id = resource.id
         
     | 
| 
       207 
     | 
    
         
            -
                            relationships_only = already_serialized?(type, id)
         
     | 
| 
       208 
     | 
    
         
            -
                            if include_linkage && !relationships_only
         
     | 
| 
       209 
     | 
    
         
            -
                              add_included_object(id, object_hash(resource, ia))
         
     | 
| 
       210 
     | 
    
         
            -
                            elsif include_linked_children || relationships_only
         
     | 
| 
       211 
     | 
    
         
            -
                              relationship_data(resource, ia)
         
     | 
| 
       212 
     | 
    
         
            -
                            end
         
     | 
| 
      
 219 
     | 
    
         
            +
                        resources.each do |resource|
         
     | 
| 
      
 220 
     | 
    
         
            +
                          next if self_referential_and_already_in_source(resource)
         
     | 
| 
      
 221 
     | 
    
         
            +
                          id = resource.id
         
     | 
| 
      
 222 
     | 
    
         
            +
                          relationships_only = already_serialized?(relationship.type, id)
         
     | 
| 
      
 223 
     | 
    
         
            +
                          if include_linkage && !relationships_only
         
     | 
| 
      
 224 
     | 
    
         
            +
                            add_included_object(id, object_hash(resource, ia))
         
     | 
| 
      
 225 
     | 
    
         
            +
                          elsif include_linked_children || relationships_only
         
     | 
| 
      
 226 
     | 
    
         
            +
                            relationships_hash(resource, ia)
         
     | 
| 
       213 
227 
     | 
    
         
             
                          end
         
     | 
| 
       214 
228 
     | 
    
         
             
                        end
         
     | 
| 
       215 
229 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -217,13 +231,6 @@ module JSONAPI 
     | 
|
| 
       217 
231 
     | 
    
         
             
                  end
         
     | 
| 
       218 
232 
     | 
    
         
             
                end
         
     | 
| 
       219 
233 
     | 
    
         | 
| 
       220 
     | 
    
         
            -
                def relationship_links(source)
         
     | 
| 
       221 
     | 
    
         
            -
                  links = {}
         
     | 
| 
       222 
     | 
    
         
            -
                  links[:self] = link_builder.self_link(source)
         
     | 
| 
       223 
     | 
    
         
            -
             
     | 
| 
       224 
     | 
    
         
            -
                  links
         
     | 
| 
       225 
     | 
    
         
            -
                end
         
     | 
| 
       226 
     | 
    
         
            -
             
     | 
| 
       227 
234 
     | 
    
         
             
                def already_serialized?(type, id)
         
     | 
| 
       228 
235 
     | 
    
         
             
                  type = format_key(type)
         
     | 
| 
       229 
236 
     | 
    
         
             
                  @included_objects.key?(type) && @included_objects[type].key?(id)
         
     | 
| 
         @@ -292,18 +299,26 @@ module JSONAPI 
     | 
|
| 
       292 
299 
     | 
    
         
             
                def foreign_key_value(source, relationship)
         
     | 
| 
       293 
300 
     | 
    
         
             
                  foreign_key = relationship.foreign_key
         
     | 
| 
       294 
301 
     | 
    
         
             
                  value = source.public_send(foreign_key)
         
     | 
| 
       295 
     | 
    
         
            -
                   
     | 
| 
      
 302 
     | 
    
         
            +
                  @id_formatter.format(value)
         
     | 
| 
       296 
303 
     | 
    
         
             
                end
         
     | 
| 
       297 
304 
     | 
    
         | 
| 
       298 
305 
     | 
    
         
             
                def foreign_key_types_and_values(source, relationship)
         
     | 
| 
       299 
306 
     | 
    
         
             
                  if relationship.is_a?(JSONAPI::Relationship::ToMany)
         
     | 
| 
       300 
307 
     | 
    
         
             
                    if relationship.polymorphic?
         
     | 
| 
       301 
     | 
    
         
            -
                      source._model.public_send(relationship.name) 
     | 
| 
       302 
     | 
    
         
            -
             
     | 
| 
      
 308 
     | 
    
         
            +
                      assoc = source._model.public_send(relationship.name)
         
     | 
| 
      
 309 
     | 
    
         
            +
                      # Avoid hitting the database again for values already pre-loaded
         
     | 
| 
      
 310 
     | 
    
         
            +
                      if assoc.respond_to?(:loaded?) and assoc.loaded?
         
     | 
| 
      
 311 
     | 
    
         
            +
                        assoc.map do |obj|
         
     | 
| 
      
 312 
     | 
    
         
            +
                          [obj.type.underscore.pluralize, @id_formatter.format(obj.id)]
         
     | 
| 
      
 313 
     | 
    
         
            +
                        end
         
     | 
| 
      
 314 
     | 
    
         
            +
                      else
         
     | 
| 
      
 315 
     | 
    
         
            +
                        assoc.pluck(:type, :id).map do |type, id|
         
     | 
| 
      
 316 
     | 
    
         
            +
                          [type.underscore.pluralize, @id_formatter.format(id)]
         
     | 
| 
      
 317 
     | 
    
         
            +
                        end
         
     | 
| 
       303 
318 
     | 
    
         
             
                      end
         
     | 
| 
       304 
319 
     | 
    
         
             
                    else
         
     | 
| 
       305 
320 
     | 
    
         
             
                      source.public_send(relationship.foreign_key).map do |value|
         
     | 
| 
       306 
     | 
    
         
            -
                        [relationship.type,  
     | 
| 
      
 321 
     | 
    
         
            +
                        [relationship.type, @id_formatter.format(value)]
         
     | 
| 
       307 
322 
     | 
    
         
             
                      end
         
     | 
| 
       308 
323 
     | 
    
         
             
                    end
         
     | 
| 
       309 
324 
     | 
    
         
             
                  end
         
     |