Make serializer lookup configurable (#1757)

This commit is contained in:
L. Preston Sego III
2016-11-16 12:38:40 -05:00
committed by Yohan Robert
parent d0de53cbb2
commit d31d741f43
10 changed files with 321 additions and 11 deletions

View File

@@ -0,0 +1,49 @@
require 'test_helper'
module ActionController
module Serialization
class LookupProcTest < ActionController::TestCase
module Api
module V3
class PostCustomSerializer < ActiveModel::Serializer
attributes :title, :body
belongs_to :author
end
class AuthorCustomSerializer < ActiveModel::Serializer
attributes :name
end
class LookupProcTestController < ActionController::Base
def implicit_namespaced_serializer
author = Author.new(name: 'Bob')
post = Post.new(title: 'New Post', body: 'Body', author: author)
render json: post
end
end
end
end
tests Api::V3::LookupProcTestController
test 'implicitly uses namespaced serializer' do
controller_namespace = lambda do |resource_class, _parent_serializer_class, namespace|
"#{namespace}::#{resource_class}CustomSerializer" if namespace
end
with_prepended_lookup(controller_namespace) do
get :implicit_namespaced_serializer
assert_serializer Api::V3::PostCustomSerializer
expected = { 'title' => 'New Post', 'body' => 'Body', 'author' => { 'name' => 'Bob' } }
actual = JSON.parse(@response.body)
assert_equal expected, actual
end
end
end
end
end

View File

@@ -15,6 +15,16 @@ module ActionController
end
end
module VHeader
class BookSerializer < ActiveModel::Serializer
attributes :title, :body
def body
'header'
end
end
end
module V3
class BookSerializer < ActiveModel::Serializer
attributes :title, :body
@@ -92,6 +102,14 @@ module ActionController
book = Book.new(title: 'New Post', body: 'Body')
render json: book
end
def namespace_set_by_request_headers
book = Book.new(title: 'New Post', body: 'Body')
version_from_header = request.headers['X-API_VERSION']
namespace = "ActionController::Serialization::NamespaceLookupTest::#{version_from_header}"
render json: book, namespace: namespace
end
end
end
end
@@ -102,6 +120,13 @@ module ActionController
@test_namespace = self.class.parent
end
test 'uses request headers to determine the namespace' do
request.env['X-API_VERSION'] = 'Api::VHeader'
get :namespace_set_by_request_headers
assert_serializer Api::VHeader::BookSerializer
end
test 'implicitly uses namespaced serializer' do
get :implicit_namespaced_serializer

View File

@@ -0,0 +1,83 @@
require_relative './benchmarking_support'
require_relative './app'
time = 10
disable_gc = true
ActiveModelSerializers.config.key_transform = :unaltered
module AmsBench
module Api
module V1
class PrimaryResourceSerializer < ActiveModel::Serializer
attributes :title, :body
has_many :has_many_relationships
end
class HasManyRelationshipSerializer < ActiveModel::Serializer
attribute :body
end
end
end
class PrimaryResourceSerializer < ActiveModel::Serializer
attributes :title, :body
has_many :has_many_relationships
class HasManyRelationshipSerializer < ActiveModel::Serializer
attribute :body
end
end
end
resource = PrimaryResource.new(
id: 1,
title: 'title',
body: 'body',
has_many_relationships: [
HasManyRelationship.new(id: 1, body: 'body1'),
HasManyRelationship.new(id: 2, body: 'body1')
]
)
serialization = lambda do
ActiveModelSerializers::SerializableResource.new(resource, serializer: AmsBench::PrimaryResourceSerializer).as_json
ActiveModelSerializers::SerializableResource.new(resource, namespace: AmsBench::Api::V1).as_json
ActiveModelSerializers::SerializableResource.new(resource).as_json
end
def clear_cache
AmsBench::PrimaryResourceSerializer.serializers_cache.clear
AmsBench::Api::V1::PrimaryResourceSerializer.serializers_cache.clear
ActiveModel::Serializer.serializers_cache.clear
end
configurable = lambda do
clear_cache
Benchmark.ams('Configurable Lookup Chain', time: time, disable_gc: disable_gc, &serialization)
end
old = lambda do
clear_cache
module ActiveModel
class Serializer
def self.serializer_lookup_chain_for(klass, namespace = nil)
chain = []
resource_class_name = klass.name.demodulize
resource_namespace = klass.name.deconstantize
serializer_class_name = "#{resource_class_name}Serializer"
chain.push("#{namespace}::#{serializer_class_name}") if namespace
chain.push("#{name}::#{serializer_class_name}") if self != ActiveModel::Serializer
chain.push("#{resource_namespace}::#{serializer_class_name}")
chain
end
end
end
Benchmark.ams('Old Lookup Chain (v0.10)', time: time, disable_gc: disable_gc, &serialization)
end
configurable.call
old.call

View File

@@ -17,6 +17,14 @@ module SerializationTesting
ActiveModelSerializers.config.jsonapi_namespace_separator = original_separator
end
def with_prepended_lookup(lookup_proc)
original_lookup = ActiveModelSerializers.config.serializer_lookup_cahin
ActiveModelSerializers.config.serializer_lookup_chain.unshift lookup_proc
yield
ensure
ActiveModelSerializers.config.serializer_lookup_cahin = original_lookup
end
# Aliased as :with_configured_adapter to clarify that
# this method tests the configured adapter.
# When not testing configuration, it may be preferable