From 80b09b1891289c16ff5b1d92c00e52e25cd865b3 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Wed, 9 Mar 2016 12:17:04 -0600 Subject: [PATCH 1/3] Never mutate controller options --- lib/action_controller/serialization.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/action_controller/serialization.rb b/lib/action_controller/serialization.rb index cc7b8ba7d..8efc21d9d 100644 --- a/lib/action_controller/serialization.rb +++ b/lib/action_controller/serialization.rb @@ -26,13 +26,13 @@ def serialization_scope respond_to?(_serialization_scope, true) end - def get_serializer(resource, options = {}) + def get_serializer(resource, serializer_options = {}) if !use_adapter? warn 'ActionController::Serialization#use_adapter? has been removed. '\ "Please pass 'adapter: false' or see ActiveSupport::SerializableResource.new" - options[:adapter] = false + serializer_options[:adapter] = false end - serializable_resource = ActiveModel::SerializableResource.new(resource, options) + serializable_resource = ActiveModel::SerializableResource.new(resource, serializer_options) if serializable_resource.serializer? serializable_resource.serialization_scope ||= serialization_scope serializable_resource.serialization_scope_name = _serialization_scope @@ -56,10 +56,12 @@ def use_adapter? [:_render_option_json, :_render_with_renderer_json].each do |renderer_method| define_method renderer_method do |resource, options| - options.fetch(:serialization_context) do - options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request, options) + options.freeze + serializer_options = options.deep_dup + serializer_options.fetch(:serialization_context) do + serializer_options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request, serializer_options) end - serializable_resource = get_serializer(resource, options) + serializable_resource = get_serializer(resource, serializer_options) super(serializable_resource, options) end end From 4b1ef59a7647b6fb35c115dcf4f6a6af1041fb1d Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Wed, 9 Mar 2016 12:41:56 -0600 Subject: [PATCH 2/3] trying to fix --- .../adapter/json_api.rb | 6 +++--- .../adapter/json_api/pagination_links.rb | 2 +- test/adapter/json_api/pagination_links_test.rb | 18 ++++++++++++------ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/active_model_serializers/adapter/json_api.rb b/lib/active_model_serializers/adapter/json_api.rb index 3233121cb..7b1b31bf0 100644 --- a/lib/active_model_serializers/adapter/json_api.rb +++ b/lib/active_model_serializers/adapter/json_api.rb @@ -128,7 +128,7 @@ def success_document(options) if is_collection && serializer.paginated? hash[:links] ||= {} - hash[:links].update(pagination_links_for(serializer, options)) + hash[:links].update(pagination_links_for(serializer)) end hash @@ -498,8 +498,8 @@ def links_for(serializer) # end # prs: # https://github.com/rails-api/active_model_serializers/pull/1041 - def pagination_links_for(serializer, options) - PaginationLinks.new(serializer.object, options[:serialization_context]).serializable_hash(options) + def pagination_links_for(serializer) + PaginationLinks.new(serializer.object, instance_options[:serialization_context]).as_json(instance_options) end # {http://jsonapi.org/format/#document-meta Docment Meta} diff --git a/lib/active_model_serializers/adapter/json_api/pagination_links.rb b/lib/active_model_serializers/adapter/json_api/pagination_links.rb index cb3ed6ba0..e9e5c9b68 100644 --- a/lib/active_model_serializers/adapter/json_api/pagination_links.rb +++ b/lib/active_model_serializers/adapter/json_api/pagination_links.rb @@ -11,7 +11,7 @@ def initialize(collection, context) @context = context end - def serializable_hash(options = {}) + def as_json(options = {}) per_page = collection.try(:per_page) || collection.try(:limit_value) || collection.size pages_from.each_with_object({}) do |(key, value), hash| params = query_parameters.merge(page: { number: value, size: per_page }).to_query diff --git a/test/adapter/json_api/pagination_links_test.rb b/test/adapter/json_api/pagination_links_test.rb index 2990d5d39..53507eefc 100644 --- a/test/adapter/json_api/pagination_links_test.rb +++ b/test/adapter/json_api/pagination_links_test.rb @@ -26,12 +26,18 @@ def mock_request(query_parameters = {}, original_url = URI) context.expect(:request_url, original_url) context.expect(:query_parameters, query_parameters) context.expect(:key_transform, nil) - @options = {} - @options[:serialization_context] = context + @serializer_options = { + serialization_context: context, + adapter: :json_api + } end def load_adapter(paginated_collection, options = {}) - options = options.merge(adapter: :json_api) + if options + options.merge!(@serializer_options) + else + options = @serializer_options + end ActiveModel::SerializableResource.new(paginated_collection, options) end @@ -106,14 +112,14 @@ def test_pagination_links_using_kaminari adapter = load_adapter(using_kaminari) mock_request - assert_equal expected_response_with_pagination_links, adapter.serializable_hash(@options) + assert_equal expected_response_with_pagination_links, adapter.serializable_hash end def test_pagination_links_using_will_paginate adapter = load_adapter(using_will_paginate) mock_request - assert_equal expected_response_with_pagination_links, adapter.serializable_hash(@options) + assert_equal expected_response_with_pagination_links, adapter.serializable_hash end def test_pagination_links_with_additional_params @@ -121,7 +127,7 @@ def test_pagination_links_with_additional_params mock_request({ test: 'test' }) assert_equal expected_response_with_pagination_links_and_additional_params, - adapter.serializable_hash(@options) + adapter.serializable_hash end def test_last_page_pagination_links_using_kaminari From 5103fe5177c28b1e01b8bcb425bfb45b79cda313 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Wed, 9 Mar 2016 12:17:04 -0600 Subject: [PATCH 3/3] Prevent controller options from being mutated - The controller options are now frozen - The serialization_context is now passed to the adapter via the adapter options and no more via as_json --- lib/action_controller/serialization.rb | 17 +- lib/active_model/serializable_resource.rb | 2 +- lib/active_model_serializers/adapter/json.rb | 2 +- .../adapter/json_api.rb | 10 +- test/adapter/json/key_case_test.rb | 23 +- test/adapter/json_api/key_case_test.rb | 349 ++++++++---------- .../adapter/json_api/pagination_links_test.rb | 87 ++--- 7 files changed, 216 insertions(+), 274 deletions(-) diff --git a/lib/action_controller/serialization.rb b/lib/action_controller/serialization.rb index 8efc21d9d..d0b8849c0 100644 --- a/lib/action_controller/serialization.rb +++ b/lib/action_controller/serialization.rb @@ -26,13 +26,13 @@ def serialization_scope respond_to?(_serialization_scope, true) end - def get_serializer(resource, serializer_options = {}) + def get_serializer(resource, serialization_options = {}) if !use_adapter? warn 'ActionController::Serialization#use_adapter? has been removed. '\ "Please pass 'adapter: false' or see ActiveSupport::SerializableResource.new" - serializer_options[:adapter] = false + serialization_options[:adapter] = false end - serializable_resource = ActiveModel::SerializableResource.new(resource, serializer_options) + serializable_resource = ActiveModel::SerializableResource.new(resource, serialization_options) if serializable_resource.serializer? serializable_resource.serialization_scope ||= serialization_scope serializable_resource.serialization_scope_name = _serialization_scope @@ -57,11 +57,14 @@ def use_adapter? [:_render_option_json, :_render_with_renderer_json].each do |renderer_method| define_method renderer_method do |resource, options| options.freeze - serializer_options = options.deep_dup - serializer_options.fetch(:serialization_context) do - serializer_options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request, serializer_options) + serialization_options = options.deep_dup + if options.key?(:serializer) + serialization_options[:serializer] = options[:serializer] end - serializable_resource = get_serializer(resource, serializer_options) + unless serialization_options.key?(:serialization_context) + serialization_options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request, serialization_options) + end + serializable_resource = get_serializer(resource, serialization_options) super(serializable_resource, options) end end diff --git a/lib/active_model/serializable_resource.rb b/lib/active_model/serializable_resource.rb index bf0e36f18..19ec060a4 100644 --- a/lib/active_model/serializable_resource.rb +++ b/lib/active_model/serializable_resource.rb @@ -2,7 +2,7 @@ require 'active_model_serializers/adapter' module ActiveModel class SerializableResource - ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter, :meta, :meta_key, :links]) + ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter, :meta, :meta_key, :links, :serialization_context]) include ActiveModelSerializers::Logging delegate :serializable_hash, :as_json, :to_json, to: :adapter diff --git a/lib/active_model_serializers/adapter/json.rb b/lib/active_model_serializers/adapter/json.rb index 7046d782c..3b2ff2ee9 100644 --- a/lib/active_model_serializers/adapter/json.rb +++ b/lib/active_model_serializers/adapter/json.rb @@ -4,7 +4,7 @@ class Json < Base def serializable_hash(options = nil) options ||= {} serialized_hash = { root => Attributes.new(serializer, instance_options).serializable_hash(options) } - transform_key_casing!(serialized_hash, options[:serialization_context]) + transform_key_casing!(serialized_hash, instance_options[:serialization_context]) end end end diff --git a/lib/active_model_serializers/adapter/json_api.rb b/lib/active_model_serializers/adapter/json_api.rb index 7b1b31bf0..eb0d5b6cd 100644 --- a/lib/active_model_serializers/adapter/json_api.rb +++ b/lib/active_model_serializers/adapter/json_api.rb @@ -1,3 +1,4 @@ +# coding: utf-8 # {http://jsonapi.org/format/ JSON API specification} # rubocop:disable Style/AsciiComments # TODO: implement! @@ -43,14 +44,13 @@ def default_key_transform # {http://jsonapi.org/format/#crud Requests are transactional, i.e. success or failure} # {http://jsonapi.org/format/#document-top-level data and errors MUST NOT coexist in the same document.} - def serializable_hash(options = nil) - options ||= {} + def serializable_hash(_options = nil) document = if serializer.success? - success_document(options) + success_document else failure_document end - transform_key_casing!(document, options[:serialization_context]) + transform_key_casing!(document, instance_options[:serialization_context]) end # {http://jsonapi.org/format/#document-top-level Primary data} @@ -68,7 +68,7 @@ def serializable_hash(options = nil) # links: toplevel_links, # jsonapi: toplevel_jsonapi # }.reject! {|_,v| v.nil? } - def success_document(options) + def success_document is_collection = serializer.respond_to?(:each) serializers = is_collection ? serializer : [serializer] primary_data, included = resource_objects_for(serializers) diff --git a/test/adapter/json/key_case_test.rb b/test/adapter/json/key_case_test.rb index 17219f3c6..fe598b0af 100644 --- a/test/adapter/json/key_case_test.rb +++ b/test/adapter/json/key_case_test.rb @@ -21,21 +21,19 @@ class PostSerializer < ActiveModel::Serializer def setup ActionController::Base.cache_store.clear @blog = Blog.new(id: 1, name: 'My Blog!!', special_attribute: 'neat') - serializer = CustomBlogSerializer.new(@blog) - @adapter = ActiveModelSerializers::Adapter::Json.new(serializer) end def test_key_transform_default mock_request assert_equal({ blog: { id: 1, special_attribute: 'neat', articles: nil } - }, @adapter.serializable_hash(@options)) + }, adapter.serializable_hash) end def test_key_transform_global_config mock_request result = with_config(key_transform: :camel_lower) do - @adapter.serializable_hash(@options) + adapter.serializable_hash end assert_equal({ blog: { id: 1, specialAttribute: 'neat', articles: nil } @@ -45,7 +43,7 @@ def test_key_transform_global_config def test_key_transform_serialization_ctx_overrides_global_config mock_request(:camel) result = with_config(key_transform: :camel_lower) do - @adapter.serializable_hash(@options) + adapter.serializable_hash end assert_equal({ Blog: { Id: 1, SpecialAttribute: 'neat', Articles: nil } @@ -56,7 +54,7 @@ def test_key_transform_undefined mock_request(:blam) result = nil assert_raises NoMethodError do - result = @adapter.serializable_hash(@options) + result = adapter.serializable_hash end end @@ -64,28 +62,33 @@ def test_key_transform_dashed mock_request(:dashed) assert_equal({ blog: { id: 1, :"special-attribute" => 'neat', articles: nil } - }, @adapter.serializable_hash(@options)) + }, adapter.serializable_hash) end def test_key_transform_unaltered mock_request(:unaltered) assert_equal({ blog: { id: 1, special_attribute: 'neat', articles: nil } - }, @adapter.serializable_hash(@options)) + }, adapter.serializable_hash) end def test_key_transform_camel mock_request(:camel) assert_equal({ Blog: { Id: 1, SpecialAttribute: 'neat', Articles: nil } - }, @adapter.serializable_hash(@options)) + }, adapter.serializable_hash) end def test_key_transform_camel_lower mock_request(:camel_lower) assert_equal({ blog: { id: 1, specialAttribute: 'neat', articles: nil } - }, @adapter.serializable_hash(@options)) + }, adapter.serializable_hash) + end + + def adapter + serializer = CustomBlogSerializer.new(@blog) + ActiveModelSerializers::Adapter::Json.new(serializer, @options || {}) end end end diff --git a/test/adapter/json_api/key_case_test.rb b/test/adapter/json_api/key_case_test.rb index 910769604..421c31a50 100644 --- a/test/adapter/json_api/key_case_test.rb +++ b/test/adapter/json_api/key_case_test.rb @@ -36,16 +36,6 @@ class CommentSerializer < ActiveModel::Serializer belongs_to :author end - def mock_request(key_transform = nil) - context = Minitest::Mock.new - context.expect(:request_url, URI) - context.expect(:query_parameters, {}) - context.expect(:key_transform, key_transform) - context.expect(:url_helpers, Rails.application.routes.url_helpers) - @options = {} - @options[:serialization_context] = context - end - def setup Rails.application.routes.draw do resources :posts do @@ -62,14 +52,14 @@ def setup publish_at: @publish_at) @comment1.post = @post @comment2.post = @post + @error_resource = ModelWithErrors.new + @error_resource.errors.add(:published_at, 'must be in the future') + @error_resource.errors.add(:title, 'must be longer') end def test_success_document_key_transform_default - mock_request - serializer = PostSerializer.new(@post) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - result = adapter.serializable_hash(@options) - assert_equal({ + result = serialize_resource(@post, options(nil, serializer: PostSerializer)) + expected_result = { data: { id: '1337', type: 'posts', @@ -86,7 +76,8 @@ def test_success_document_key_transform_default data: [ { id: '7', type: 'comments' }, { id: '12', type: 'comments' } - ] } + ] + } }, links: { self: 'http://example.com/posts/1337', @@ -95,17 +86,15 @@ def test_success_document_key_transform_default }, meta: { rating: 5, :"favorite-count" => 10 } } - }, result) + } + assert_equal(expected_result, result) end def test_success_document_key_transform_global_config - mock_request result = with_config(key_transform: :camel_lower) do - serializer = PostSerializer.new(@post) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - adapter.serializable_hash(@options) + serialize_resource(@post, options(nil, serializer: PostSerializer)) end - assert_equal({ + expected_result = { data: { id: '1337', type: 'posts', @@ -122,7 +111,8 @@ def test_success_document_key_transform_global_config data: [ { id: '7', type: 'comments' }, { id: '12', type: 'comments' } - ] } + ] + } }, links: { self: 'http://example.com/posts/1337', @@ -131,17 +121,15 @@ def test_success_document_key_transform_global_config }, meta: { rating: 5, favoriteCount: 10 } } - }, result) + } + assert_equal(expected_result, result) end def test_success_doc_key_transform_serialization_ctx_overrides_global - mock_request(:camel) result = with_config(key_transform: :camel_lower) do - serializer = PostSerializer.new(@post) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - adapter.serializable_hash(@options) + serialize_resource(@post, options(:camel, serializer: PostSerializer)) end - assert_equal({ + expected_result = { Data: { Id: '1337', Type: 'posts', @@ -158,7 +146,8 @@ def test_success_doc_key_transform_serialization_ctx_overrides_global Data: [ { Id: '7', Type: 'comments' }, { Id: '12', Type: 'comments' } - ] } + ] + } }, Links: { Self: 'http://example.com/posts/1337', @@ -167,15 +156,13 @@ def test_success_doc_key_transform_serialization_ctx_overrides_global }, Meta: { Rating: 5, FavoriteCount: 10 } } - }, result) + } + assert_equal(expected_result, result) end def test_success_document_key_transform_dashed - mock_request(:dashed) - serializer = PostSerializer.new(@post) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - result = adapter.serializable_hash(@options) - assert_equal({ + result = serialize_resource(@post, options(:dashed, serializer: PostSerializer)) + expected_result = { data: { id: '1337', type: 'posts', @@ -192,7 +179,8 @@ def test_success_document_key_transform_dashed data: [ { id: '7', type: 'comments' }, { id: '12', type: 'comments' } - ] } + ] + } }, links: { self: 'http://example.com/posts/1337', @@ -201,15 +189,13 @@ def test_success_document_key_transform_dashed }, meta: { rating: 5, :"favorite-count" => 10 } } - }, result) + } + assert_equal(expected_result, result) end def test_success_document_key_transform_unaltered - mock_request(:unaltered) - serializer = PostSerializer.new(@post) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - result = adapter.serializable_hash(@options) - assert_equal({ + result = serialize_resource(@post, options(:unaltered, serializer: PostSerializer)) + expected_result = { data: { id: '1337', type: 'posts', @@ -226,7 +212,8 @@ def test_success_document_key_transform_unaltered data: [ { id: '7', type: 'comments' }, { id: '12', type: 'comments' } - ] } + ] + } }, links: { self: 'http://example.com/posts/1337', @@ -235,24 +222,19 @@ def test_success_document_key_transform_unaltered }, meta: { rating: 5, favorite_count: 10 } } - }, result) + } + assert_equal(expected_result, result) end def test_success_document_key_transform_undefined - mock_request(:zoot) - serializer = PostSerializer.new(@post) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) assert_raises NoMethodError do - adapter.serializable_hash(@options) + serialize_resource(@post, options(:zoot, serializer: PostSerializer)) end end def test_success_document_key_transform_camel - mock_request(:camel) - serializer = PostSerializer.new(@post) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - result = adapter.serializable_hash(@options) - assert_equal({ + result = serialize_resource(@post, options(:camel, serializer: PostSerializer)) + expected_result = { Data: { Id: '1337', Type: 'posts', @@ -269,7 +251,8 @@ def test_success_document_key_transform_camel Data: [ { Id: '7', Type: 'comments' }, { Id: '12', Type: 'comments' } - ] } + ] + } }, Links: { Self: 'http://example.com/posts/1337', @@ -278,15 +261,13 @@ def test_success_document_key_transform_camel }, Meta: { Rating: 5, FavoriteCount: 10 } } - }, result) + } + assert_equal(expected_result, result) end def test_success_document_key_transform_camel_lower - mock_request(:camel_lower) - serializer = PostSerializer.new(@post) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - result = adapter.serializable_hash(@options) - assert_equal({ + result = serialize_resource(@post, options(:camel_lower, serializer: PostSerializer)) + expected_result = { data: { id: '1337', type: 'posts', @@ -303,7 +284,8 @@ def test_success_document_key_transform_camel_lower data: [ { id: '7', type: 'comments' }, { id: '12', type: 'comments' } - ] } + ] + } }, links: { self: 'http://example.com/posts/1337', @@ -312,187 +294,156 @@ def test_success_document_key_transform_camel_lower }, meta: { rating: 5, favoriteCount: 10 } } - }, result) + } + assert_equal(expected_result, result) end def test_error_document_key_transform_default - mock_request - resource = ModelWithErrors.new - resource.errors.add(:published_at, 'must be in the future') - resource.errors.add(:title, 'must be longer') - serializer = ActiveModel::Serializer::ErrorSerializer.new(resource) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - result = adapter.serializable_hash(@options) - expected_errors_object = - { :errors => - [ - { - :source => { :pointer => '/data/attributes/published_at' }, - :detail => 'must be in the future' }, - { - :source => { :pointer => '/data/attributes/title' }, - :detail => 'must be longer' - } - ] - } + result = serialize_resource(@error_resource, options(nil, serializer: ActiveModel::Serializer::ErrorSerializer)) + expected_errors_object = { + errors: [ + { + source: { pointer: '/data/attributes/published_at' }, + detail: 'must be in the future' + }, + { + source: { pointer: '/data/attributes/title' }, + detail: 'must be longer' + } + ] + } assert_equal expected_errors_object, result end def test_error_document_key_transform_global_config - mock_request result = with_config(key_transform: :camel) do - resource = ModelWithErrors.new - resource.errors.add(:published_at, 'must be in the future') - resource.errors.add(:title, 'must be longer') - serializer = ActiveModel::Serializer::ErrorSerializer.new(resource) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - adapter.serializable_hash(@options) + serialize_resource(@error_resource, options(nil, serializer: ActiveModel::Serializer::ErrorSerializer)) end - expected_errors_object = - { :Errors => - [ - { - :Source => { :Pointer => '/data/attributes/published_at' }, - :Detail => 'must be in the future' - }, - { - :Source => { :Pointer => '/data/attributes/title' }, - :Detail => 'must be longer' - } - ] - } + expected_errors_object = { + Errors: [ + { + Source: { Pointer: '/data/attributes/published_at' }, + Detail: 'must be in the future' + }, + { + Source: { Pointer: '/data/attributes/title' }, + Detail: 'must be longer' + } + ] + } assert_equal expected_errors_object, result end def test_error_document_key_transform_serialization_ctx_overrides_global - mock_request(:camel) result = with_config(key_transform: :camel_lower) do - resource = ModelWithErrors.new - resource.errors.add(:published_at, 'must be in the future') - resource.errors.add(:title, 'must be longer') - serializer = ActiveModel::Serializer::ErrorSerializer.new(resource) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - adapter.serializable_hash(@options) + serialize_resource(@error_resource, options(:camel, serializer: ActiveModel::Serializer::ErrorSerializer)) end - expected_errors_object = - { :Errors => - [ - { - :Source => { :Pointer => '/data/attributes/published_at' }, - :Detail => 'must be in the future' - }, - { - :Source => { :Pointer => '/data/attributes/title' }, - :Detail => 'must be longer' - } - ] - } + expected_errors_object = { + Errors: [ + { + Source: { Pointer: '/data/attributes/published_at' }, + Detail: 'must be in the future' + }, + { + Source: { Pointer: '/data/attributes/title' }, + Detail: 'must be longer' + } + ] + } assert_equal expected_errors_object, result end def test_error_document_key_transform_dashed - mock_request(:dashed) - - resource = ModelWithErrors.new - resource.errors.add(:published_at, 'must be in the future') - resource.errors.add(:title, 'must be longer') - - serializer = ActiveModel::Serializer::ErrorSerializer.new(resource) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - result = adapter.serializable_hash(@options) - - expected_errors_object = - { :errors => - [ - { - :source => { :pointer => '/data/attributes/published_at' }, - :detail => 'must be in the future' - }, - { - :source => { :pointer => '/data/attributes/title' }, - :detail => 'must be longer' - } - ] + result = serialize_resource(@error_resource, options(:dashed, serializer: ActiveModel::Serializer::ErrorSerializer)) + expected_errors_object = { + errors: [ + { + source: { pointer: '/data/attributes/published_at' }, + detail: 'must be in the future' + }, + { + source: { pointer: '/data/attributes/title' }, + detail: 'must be longer' + } + ] } assert_equal expected_errors_object, result end def test_error_document_key_transform_unaltered - mock_request(:unaltered) - - resource = ModelWithErrors.new - resource.errors.add(:published_at, 'must be in the future') - resource.errors.add(:title, 'must be longer') - - serializer = ActiveModel::Serializer::ErrorSerializer.new(resource) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - result = adapter.serializable_hash(@options) - - expected_errors_object = - { :errors => - [ - { :source => { :pointer => '/data/attributes/published_at' }, :detail => 'must be in the future' }, - { :source => { :pointer => '/data/attributes/title' }, :detail => 'must be longer' } - ] + result = serialize_resource(@error_resource, options(:unaltered, serializer: ActiveModel::Serializer::ErrorSerializer)) + expected_errors_object = { + errors: [ + { + source: { pointer: '/data/attributes/published_at' }, + detail: 'must be in the future' + }, + { + source: { pointer: '/data/attributes/title' }, + detail: 'must be longer' + } + ] } assert_equal expected_errors_object, result end def test_error_document_key_transform_undefined - mock_request(:krazy) - - resource = ModelWithErrors.new - resource.errors.add(:published_at, 'must be in the future') - resource.errors.add(:title, 'must be longer') - - serializer = ActiveModel::Serializer::ErrorSerializer.new(resource) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - assert_raises NoMethodError do - adapter.serializable_hash(@options) + serialize_resource(@error_resource, options(:krazy, serializer: ActiveModel::Serializer::ErrorSerializer)) end end def test_error_document_key_transform_camel - mock_request(:camel) - - resource = ModelWithErrors.new - resource.errors.add(:published_at, 'must be in the future') - resource.errors.add(:title, 'must be longer') - - serializer = ActiveModel::Serializer::ErrorSerializer.new(resource) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - result = adapter.serializable_hash(@options) - - expected_errors_object = - { :Errors => + result = serialize_resource(@error_resource, options(:camel, serializer: ActiveModel::Serializer::ErrorSerializer)) + expected_errors_object = { + Errors: [ - { :Source => { :Pointer => '/data/attributes/published_at' }, :Detail => 'must be in the future' }, - { :Source => { :Pointer => '/data/attributes/title' }, :Detail => 'must be longer' } + { + Source: { Pointer: '/data/attributes/published_at' }, + Detail: 'must be in the future' + }, + { + Source: { Pointer: '/data/attributes/title' }, + Detail: 'must be longer' + } ] } assert_equal expected_errors_object, result end def test_error_document_key_transform_camel_lower - mock_request(:camel_lower) + result = serialize_resource(@error_resource, options(:camel_lower, serializer: ActiveModel::Serializer::ErrorSerializer)) + expected_errors_object = { + errors: [ + { + source: { pointer: '/data/attributes/published_at' }, + detail: 'must be in the future' + }, + { + source: { pointer: '/data/attributes/title' }, + detail: 'must be longer' + } + ] + } + assert_equal expected_errors_object, result + end - resource = ModelWithErrors.new - resource.errors.add(:published_at, 'must be in the future') - resource.errors.add(:title, 'must be longer') + private - serializer = ActiveModel::Serializer::ErrorSerializer.new(resource) - adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) - result = adapter.serializable_hash(@options) + def options(key_transform = nil, extra_options = {}) + context = Minitest::Mock.new + context.expect(:request_url, URI) + context.expect(:query_parameters, {}) + context.expect(:key_transform, key_transform) + context.expect(:url_helpers, Rails.application.routes.url_helpers) + { + serialization_context: context, + adapter: :json_api + }.merge(extra_options) + end - expected_errors_object = - { :errors => - [ - { :source => { :pointer => '/data/attributes/published_at' }, :detail => 'must be in the future' }, - { :source => { :pointer => '/data/attributes/title' }, :detail => 'must be longer' } - ] - } - assert_equal expected_errors_object, result + def serialize_resource(resource, options) + ActiveModel::SerializableResource.new(resource, options).as_json end end end diff --git a/test/adapter/json_api/pagination_links_test.rb b/test/adapter/json_api/pagination_links_test.rb index 53507eefc..31550a525 100644 --- a/test/adapter/json_api/pagination_links_test.rb +++ b/test/adapter/json_api/pagination_links_test.rb @@ -21,9 +21,41 @@ def setup ] end - def mock_request(query_parameters = {}, original_url = URI) + def test_pagination_links_using_kaminari + actual_response = serialize_resource(using_kaminari, options) + assert_equal expected_response_with_pagination_links, actual_response + end + + def test_pagination_links_using_will_paginate + actual_response = serialize_resource(using_will_paginate, options) + assert_equal expected_response_with_pagination_links, actual_response + end + + def test_pagination_links_with_additional_params + actual_response = serialize_resource(using_will_paginate, options(test: 'test')) + assert_equal expected_response_with_pagination_links_and_additional_params, actual_response + end + + def test_last_page_pagination_links_using_kaminari + actual_response = serialize_resource(using_kaminari(3), options) + assert_equal expected_response_with_last_page_pagination_links, actual_response + end + + def test_last_page_pagination_links_using_will_paginate + actual_response = serialize_resource(using_will_paginate(3), options) + assert_equal expected_response_with_last_page_pagination_links, actual_response + end + + def test_not_showing_pagination_links + actual_response = serialize_resource(@array) + assert_equal expected_response_without_pagination_links, actual_response + end + + private + + def options(query_parameters = {}) context = Minitest::Mock.new - context.expect(:request_url, original_url) + context.expect(:request_url, URI) context.expect(:query_parameters, query_parameters) context.expect(:key_transform, nil) @serializer_options = { @@ -32,13 +64,8 @@ def mock_request(query_parameters = {}, original_url = URI) } end - def load_adapter(paginated_collection, options = {}) - if options - options.merge!(@serializer_options) - else - options = @serializer_options - end - ActiveModel::SerializableResource.new(paginated_collection, options) + def serialize_resource(paginated_collection, options = { adapter: :json_api }) + ActiveModel::SerializableResource.new(paginated_collection, options).as_json end def using_kaminari(page = 2) @@ -107,48 +134,6 @@ def expected_response_with_last_page_pagination_links hash.merge! last_page_links end end - - def test_pagination_links_using_kaminari - adapter = load_adapter(using_kaminari) - - mock_request - assert_equal expected_response_with_pagination_links, adapter.serializable_hash - end - - def test_pagination_links_using_will_paginate - adapter = load_adapter(using_will_paginate) - - mock_request - assert_equal expected_response_with_pagination_links, adapter.serializable_hash - end - - def test_pagination_links_with_additional_params - adapter = load_adapter(using_will_paginate) - - mock_request({ test: 'test' }) - assert_equal expected_response_with_pagination_links_and_additional_params, - adapter.serializable_hash - end - - def test_last_page_pagination_links_using_kaminari - adapter = load_adapter(using_kaminari(3)) - - mock_request - assert_equal expected_response_with_last_page_pagination_links, adapter.serializable_hash(@options) - end - - def test_last_page_pagination_links_using_will_paginate - adapter = load_adapter(using_will_paginate(3)) - - mock_request - assert_equal expected_response_with_last_page_pagination_links, adapter.serializable_hash(@options) - end - - def test_not_showing_pagination_links - adapter = load_adapter(@array) - - assert_equal expected_response_without_pagination_links, adapter.serializable_hash - end end end end