-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make serializer lookup configurable (#1757)
- Loading branch information
1 parent
d0de53c
commit d31d741
Showing
10 changed files
with
321 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
module ActiveModelSerializers | ||
module LookupChain | ||
# Standard appending of Serializer to the resource name. | ||
# | ||
# Example: | ||
# Author => AuthorSerializer | ||
BY_RESOURCE = lambda do |resource_class, _serializer_class, _namespace| | ||
serializer_from(resource_class) | ||
end | ||
|
||
# Uses the namespace of the resource to find the serializer | ||
# | ||
# Example: | ||
# British::Author => British::AuthorSerializer | ||
BY_RESOURCE_NAMESPACE = lambda do |resource_class, _serializer_class, _namespace| | ||
resource_namespace = namespace_for(resource_class) | ||
serializer_name = serializer_from(resource_class) | ||
|
||
"#{resource_namespace}::#{serializer_name}" | ||
end | ||
|
||
# Uses the controller namespace of the resource to find the serializer | ||
# | ||
# Example: | ||
# Api::V3::AuthorsController => Api::V3::AuthorSerializer | ||
BY_NAMESPACE = lambda do |resource_class, _serializer_class, namespace| | ||
resource_name = resource_class_name(resource_class) | ||
namespace ? "#{namespace}::#{resource_name}Serializer" : nil | ||
end | ||
|
||
# Allows for serializers to be defined in parent serializers | ||
# - useful if a relationship only needs a different set of attributes | ||
# than if it were rendered independently. | ||
# | ||
# Example: | ||
# class BlogSerializer < ActiveModel::Serializer | ||
# class AuthorSerialier < ActiveModel::Serializer | ||
# ... | ||
# end | ||
# | ||
# belongs_to :author | ||
# ... | ||
# end | ||
# | ||
# The belongs_to relationship would be rendered with | ||
# BlogSerializer::AuthorSerialier | ||
BY_PARENT_SERIALIZER = lambda do |resource_class, serializer_class, _namespace| | ||
return if serializer_class == ActiveModel::Serializer | ||
|
||
serializer_name = serializer_from(resource_class) | ||
"#{serializer_class}::#{serializer_name}" | ||
end | ||
|
||
DEFAULT = [ | ||
BY_PARENT_SERIALIZER, | ||
BY_NAMESPACE, | ||
BY_RESOURCE_NAMESPACE, | ||
BY_RESOURCE | ||
].freeze | ||
|
||
module_function | ||
|
||
def namespace_for(klass) | ||
klass.name.deconstantize | ||
end | ||
|
||
def resource_class_name(klass) | ||
klass.name.demodulize | ||
end | ||
|
||
def serializer_from_resource_name(name) | ||
"#{name}Serializer" | ||
end | ||
|
||
def serializer_from(klass) | ||
name = resource_class_name(klass) | ||
serializer_from_resource_name(name) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters