From 70c97414c883c1934765759ef72b60226402c2b7 Mon Sep 17 00:00:00 2001 From: Ben Mills Date: Thu, 31 Mar 2016 14:24:31 -0600 Subject: [PATCH] Apply key transforms to keys referenced in values --- CHANGELOG.md | 4 + active_model_serializers.gemspec | 6 + docs/general/configuration_options.md | 22 ++-- docs/general/key_transform.md | 34 ----- docs/general/key_transforms.md | 40 ++++++ lib/active_model_serializers/adapter/base.rb | 41 +++--- lib/active_model_serializers/adapter/json.rb | 2 +- .../adapter/json_api.rb | 55 ++++---- .../adapter/json_api/deserialization.rb | 8 +- .../adapter/json_api/error.rb | 4 +- .../adapter/json_api/relationship.rb | 26 ++-- .../adapter/json_api/resource_identifier.rb | 5 +- lib/active_model_serializers/key_transform.rb | 50 ++++--- .../serialization_context.rb | 1 - ...ey_transform_test.rb => transform_test.rb} | 54 ++++---- .../key_transform_test.rb | 123 ++++++++++++++++++ .../{key_case_test.rb => transform_test.rb} | 20 +-- test/adapter/json_api/has_many_test.rb | 2 +- test/adapter/json_api/has_one_test.rb | 2 +- test/adapter/json_api/linked_test.rb | 10 +- test/adapter/json_api/links_test.rb | 4 +- .../adapter/json_api/pagination_links_test.rb | 1 - test/adapter/json_api/relationship_test.rb | 5 +- .../json_api/resource_identifier_test.rb | 6 +- test/adapter/json_api/resource_meta_test.rb | 6 +- .../{key_case_test.rb => transform_test.rb} | 74 +++++------ test/benchmark/bm_caching.rb | 3 +- test/benchmark/bm_transform.rb | 34 +++++ test/benchmark/controllers.rb | 2 +- test/benchmark/fixtures.rb | 18 ++- 30 files changed, 439 insertions(+), 223 deletions(-) delete mode 100644 docs/general/key_transform.md create mode 100644 docs/general/key_transforms.md rename test/action_controller/json_api/{key_transform_test.rb => transform_test.rb} (75%) create mode 100644 test/active_model_serializers/key_transform_test.rb rename test/adapter/json/{key_case_test.rb => transform_test.rb} (85%) rename test/adapter/json_api/{key_case_test.rb => transform_test.rb} (88%) create mode 100644 test/benchmark/bm_transform.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 244b3850a..f6221deb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,11 @@ Breaking changes: +- [#1645](https://github.com/rails-api/active_model_serializers/pull/1645) Changed :dashed key transform to :dash. (@remear) +- [#1574](https://github.com/rails-api/active_model_serializers/pull/1574) Default key case for the JsonApi adapter changed to dashed. (@remear) + Features: +- [#1645](https://github.com/rails-api/active_model_serializers/pull/1645) Transform keys referenced in values. (@remear) - [#1650](https://github.com/rails-api/active_model_serializers/pull/1650) Fix serialization scope options `scope`, `scope_name` take precedence over `serialization_scope` in the controller. Fix tests that required tearing down dynamic methods. (@bf4) diff --git a/active_model_serializers.gemspec b/active_model_serializers.gemspec index c92edbbf6..49f3eddfd 100644 --- a/active_model_serializers.gemspec +++ b/active_model_serializers.gemspec @@ -57,4 +57,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'grape', ['>= 0.13', '< 1.0'] spec.add_development_dependency 'json_schema' spec.add_development_dependency 'rake', ['>= 10.0', '< 12.0'] + + spec.post_install_message = <<-EOF +NOTE: The default key case for the JsonApi adapter has changed to dashed. +See https://github.com/rails-api/active_model_serializers/blob/master/docs/general/key_transform.md +for more information on configuring this behavior. +EOF end diff --git a/docs/general/configuration_options.md b/docs/general/configuration_options.md index b9b7802dc..82719fb24 100644 --- a/docs/general/configuration_options.md +++ b/docs/general/configuration_options.md @@ -30,20 +30,24 @@ When `false`, serializers must be explicitly specified. ##### key_transform -The [key transform](key_transform.md) to use. +The [key transform](key_transforms.md) to use. -Possible values: -- `:camel` - ExampleKey -- `:camel_lower` - exampleKey -- `:dashed` - example-key -- `:unaltered` - the original, unaltered key -- `nil` - use the adapter default +| Option | Result | +|----|----| +| `:camel` | ExampleKey | +| `:camel_lower` | exampleKey | +| `:dash` | example-key | +| `:unaltered` | the original, unaltered key | +| `:underscore` | example_key | +| `nil` | use the adapter default | Each adapter has a default key transform configured: -- `Json` - `:unaltered` -- `JsonApi` - `:dashed` +| Adapter | Default Key Transform | +|----|----| +| `Json` | `:unaltered` | +| `JsonApi` | `:dash` | `config.key_transform` is a global override of the adapter default. Adapters still prefer the render option `:key_transform` over this setting. diff --git a/docs/general/key_transform.md b/docs/general/key_transform.md deleted file mode 100644 index 022b7688a..000000000 --- a/docs/general/key_transform.md +++ /dev/null @@ -1,34 +0,0 @@ -[Back to Guides](../README.md) - -# Key Transforms - -Key transforms modify the keys in serialized responses. - -Provided key transforms: - -- `:camel` - ExampleKey -- `:camel_lower` - exampleKey -- `:dashed` - example-key -- `:unaltered` - the original, unaltered key -- `nil` - use the adapter default - -Key translation precedence is as follows: - -##### SerializableResource option - -`key_transform` is provided as an option via render. - -```render json: posts, each_serializer: PostSerializer, key_transform: :camel_lower``` - -##### Configuration option - -`key_transform` is set in `ActiveModelSerializers.config.key_transform`. - -```ActiveModelSerializers.config.key_transform = :camel_lower``` - -##### Adapter default - -Each adapter has a default key transform configured: - -- `Json` - `:unaltered` -- `JsonApi` - `:dashed` diff --git a/docs/general/key_transforms.md b/docs/general/key_transforms.md new file mode 100644 index 000000000..fd1be2d77 --- /dev/null +++ b/docs/general/key_transforms.md @@ -0,0 +1,40 @@ +[Back to Guides](../README.md) + +# Key Transforms + +Key Transforms modify the casing of keys and keys referenced in values in +serialized responses. + +Provided key transforms: + +| Option | Result | +|----|----| +| `:camel` | ExampleKey | +| `:camel_lower` | exampleKey | +| `:dash` | example-key | +| `:unaltered` | the original, unaltered key | +| `:underscore` | example_key | +| `nil` | use the adapter default | + +Key translation precedence is as follows: + +##### Adapter option + +`key_transform` is provided as an option via render. + +```render json: posts, each_serializer: PostSerializer, key_transform: :camel_lower``` + +##### Configuration option + +`key_transform` is set in `ActiveModelSerializers.config.key_transform`. + +```ActiveModelSerializers.config.key_transform = :camel_lower``` + +##### Adapter default + +Each adapter has a default transform configured: + +| Adapter | Default Key Transform | +|----|----| +| `Json` | `:unaltered` | +| `JsonApi` | `:dash` | diff --git a/lib/active_model_serializers/adapter/base.rb b/lib/active_model_serializers/adapter/base.rb index 71eb59abf..f63b24990 100644 --- a/lib/active_model_serializers/adapter/base.rb +++ b/lib/active_model_serializers/adapter/base.rb @@ -58,25 +58,32 @@ def include_meta(json) json end - def default_key_transform - :unaltered - end + class << self + # Sets the default transform for the adapter. + # + # @return [Symbol] the default transform for the adapter + def default_key_transform + :unaltered + end - # Determines the transform to use in order of precedence: - # serialization context, global config, adapter default. - # - # @param serialization_context [Object] the SerializationContext - # @return [Symbol] the transform to use - def key_transform(serialization_context) - serialization_context.key_transform || - ActiveModelSerializers.config.key_transform || - default_key_transform - end + # Determines the transform to use in order of precedence: + # adapter option, global config, adapter default. + # + # @param options [Object] + # @return [Symbol] the transform to use + def transform(options) + return options[:key_transform] if options && options[:key_transform] + ActiveModelSerializers.config.key_transform || default_key_transform + end - def transform_key_casing!(value, serialization_context) - return value unless serialization_context - transform = key_transform(serialization_context) - KeyTransform.send(transform, value) + # Transforms the casing of the supplied value. + # + # @param value [Object] the value to be transformed + # @param options [Object] serializable resource options + # @return [Symbol] the default transform for the adapter + def transform_key_casing!(value, options) + KeyTransform.send(transform(options), value) + end end end end diff --git a/lib/active_model_serializers/adapter/json.rb b/lib/active_model_serializers/adapter/json.rb index 7046d782c..5d182a515 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]) + self.class.transform_key_casing!(serialized_hash, options) end end end diff --git a/lib/active_model_serializers/adapter/json_api.rb b/lib/active_model_serializers/adapter/json_api.rb index 3233121cb..c324798ca 100644 --- a/lib/active_model_serializers/adapter/json_api.rb +++ b/lib/active_model_serializers/adapter/json_api.rb @@ -37,8 +37,8 @@ def initialize(serializer, options = {}) @fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields)) end - def default_key_transform - :dashed + def self.default_key_transform + :dash end # {http://jsonapi.org/format/#crud Requests are transactional, i.e. success or failure} @@ -48,9 +48,9 @@ def serializable_hash(options = nil) document = if serializer.success? success_document(options) else - failure_document + failure_document(options) end - transform_key_casing!(document, options[:serialization_context]) + self.class.transform_key_casing!(document, options) end # {http://jsonapi.org/format/#document-top-level Primary data} @@ -71,7 +71,7 @@ def serializable_hash(options = nil) def success_document(options) is_collection = serializer.respond_to?(:each) serializers = is_collection ? serializer : [serializer] - primary_data, included = resource_objects_for(serializers) + primary_data, included = resource_objects_for(serializers, options) hash = {} # toplevel_data @@ -148,7 +148,7 @@ def success_document(options) # }.reject! {|_,v| v.nil? } # prs: # https://github.com/rails-api/active_model_serializers/pull/1004 - def failure_document + def failure_document(options) hash = {} # PR Please :) # Jsonapi.add!(hash) @@ -163,10 +163,10 @@ def failure_document # ] if serializer.respond_to?(:each) hash[:errors] = serializer.flat_map do |error_serializer| - Error.resource_errors(error_serializer) + Error.resource_errors(error_serializer, options) end else - hash[:errors] = Error.resource_errors(serializer) + hash[:errors] = Error.resource_errors(serializer, options) end hash end @@ -224,21 +224,21 @@ def fragment_cache(cached_hash, non_cached_hash) # [x] url helpers https://github.com/rails-api/active_model_serializers/issues/1269 # meta # [x] https://github.com/rails-api/active_model_serializers/pull/1340 - def resource_objects_for(serializers) + def resource_objects_for(serializers, options) @primary = [] @included = [] @resource_identifiers = Set.new - serializers.each { |serializer| process_resource(serializer, true) } - serializers.each { |serializer| process_relationships(serializer, @include_tree) } + serializers.each { |serializer| process_resource(serializer, true, options) } + serializers.each { |serializer| process_relationships(serializer, @include_tree, options) } [@primary, @included] end - def process_resource(serializer, primary) - resource_identifier = ResourceIdentifier.new(serializer).as_json + def process_resource(serializer, primary, options) + resource_identifier = ResourceIdentifier.new(serializer, options).as_json return false unless @resource_identifiers.add?(resource_identifier) - resource_object = resource_object_for(serializer) + resource_object = resource_object_for(serializer, options) if primary @primary << resource_object else @@ -248,21 +248,21 @@ def process_resource(serializer, primary) true end - def process_relationships(serializer, include_tree) + def process_relationships(serializer, include_tree, options) serializer.associations(include_tree).each do |association| - process_relationship(association.serializer, include_tree[association.key]) + process_relationship(association.serializer, include_tree[association.key], options) end end - def process_relationship(serializer, include_tree) + def process_relationship(serializer, include_tree, options) if serializer.respond_to?(:each) - serializer.each { |s| process_relationship(s, include_tree) } + serializer.each { |s| process_relationship(s, include_tree, options) } return end return unless serializer && serializer.object - return unless process_resource(serializer, false) + return unless process_resource(serializer, false, options) - process_relationships(serializer, include_tree) + process_relationships(serializer, include_tree, options) end # {http://jsonapi.org/format/#document-resource-object-attributes Document Resource Object Attributes} @@ -286,9 +286,9 @@ def attributes_for(serializer, fields) end # {http://jsonapi.org/format/#document-resource-objects Document Resource Objects} - def resource_object_for(serializer) + def resource_object_for(serializer, options) resource_object = cache_check(serializer) do - resource_object = ResourceIdentifier.new(serializer).as_json + resource_object = ResourceIdentifier.new(serializer, options).as_json requested_fields = fieldset && fieldset.fields_for(resource_object[:type]) attributes = attributes_for(serializer, requested_fields) @@ -297,7 +297,7 @@ def resource_object_for(serializer) end requested_associations = fieldset.fields_for(resource_object[:type]) || '*' - relationships = relationships_for(serializer, requested_associations) + relationships = relationships_for(serializer, requested_associations, options) resource_object[:relationships] = relationships if relationships.any? links = links_for(serializer) @@ -425,15 +425,16 @@ def resource_object_for(serializer) # id: 'required-id', # meta: meta # }.reject! {|_,v| v.nil? } - def relationships_for(serializer, requested_associations) + def relationships_for(serializer, requested_associations, options) include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(requested_associations) serializer.associations(include_tree).each_with_object({}) do |association, hash| hash[association.key] = Relationship.new( serializer, association.serializer, - association.options, - association.links, - association.meta + options, + options: association.options, + links: association.links, + meta: association.meta ).as_json end end diff --git a/lib/active_model_serializers/adapter/json_api/deserialization.rb b/lib/active_model_serializers/adapter/json_api/deserialization.rb index 7b187df2c..2e0e531dd 100644 --- a/lib/active_model_serializers/adapter/json_api/deserialization.rb +++ b/lib/active_model_serializers/adapter/json_api/deserialization.rb @@ -182,14 +182,14 @@ def parse_relationship(assoc_name, assoc_data, options) prefix_key = field_key(assoc_name, options).to_s.singularize hash = if assoc_data.is_a?(Array) - { "#{prefix_key}_ids".to_sym => assoc_data.map { |ri| ri[:id] } } + { "#{prefix_key}_ids".to_sym => assoc_data.map { |ri| ri['id'] } } else - { "#{prefix_key}_id".to_sym => assoc_data && assoc_data.is_a?(Hash) ? assoc_data[:id] : nil } + { "#{prefix_key}_id".to_sym => assoc_data ? assoc_data['id'] : nil } end polymorphic = (options[:polymorphic] || []).include?(assoc_name.to_sym) if polymorphic - hash["#{prefix_key}_type".to_sym] = assoc_data.present? ? assoc_data[:type] : nil + hash["#{prefix_key}_type".to_sym] = assoc_data.present? ? assoc_data['type'] : nil end hash @@ -198,7 +198,7 @@ def parse_relationship(assoc_name, assoc_data, options) # @api private def parse_relationships(relationships, options) transform_keys(relationships, options) - .map { |(k, v)| parse_relationship(k, v[:data], options) } + .map { |(k, v)| parse_relationship(k, v['data'], options) } .reduce({}, :merge) end diff --git a/lib/active_model_serializers/adapter/json_api/error.rb b/lib/active_model_serializers/adapter/json_api/error.rb index 41c5ec5dc..c7b18716c 100644 --- a/lib/active_model_serializers/adapter/json_api/error.rb +++ b/lib/active_model_serializers/adapter/json_api/error.rb @@ -10,8 +10,10 @@ module Error # # @param [ActiveModel::Serializer::ErrorSerializer] error_serializer # @return [Array>] i.e. attribute_name, [attribute_errors] - def self.resource_errors(error_serializer) + def self.resource_errors(error_serializer, options) error_serializer.as_json.flat_map do |attribute_name, attribute_errors| + attribute_name = JsonApi.send(:transform_key_casing!, attribute_name, + options) attribute_error_objects(attribute_name, attribute_errors) end end diff --git a/lib/active_model_serializers/adapter/json_api/relationship.rb b/lib/active_model_serializers/adapter/json_api/relationship.rb index 30e5a0917..39e7e2551 100644 --- a/lib/active_model_serializers/adapter/json_api/relationship.rb +++ b/lib/active_model_serializers/adapter/json_api/relationship.rb @@ -6,21 +6,22 @@ class Relationship # {http://jsonapi.org/format/#document-links Document Links} # {http://jsonapi.org/format/#document-resource-object-linkage Document Resource Relationship Linkage} # {http://jsonapi.org/format/#document-meta Docment Meta} - def initialize(parent_serializer, serializer, options = {}, links = {}, meta = nil) + def initialize(parent_serializer, serializer, serializable_resource_options, args = {}) @object = parent_serializer.object @scope = parent_serializer.scope - - @options = options - @data = data_for(serializer, options) - @links = links.each_with_object({}) do |(key, value), hash| + @association_options = args.fetch(:options, {}) + @serializable_resource_options = serializable_resource_options + @data = data_for(serializer) + @links = args.fetch(:links, {}).each_with_object({}) do |(key, value), hash| hash[key] = ActiveModelSerializers::Adapter::JsonApi::Link.new(parent_serializer, value).as_json end + meta = args.fetch(:meta, nil) @meta = meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta end def as_json hash = {} - hash[:data] = data if options[:include_data] + hash[:data] = data if association_options[:include_data] links = self.links hash[:links] = links if links.any? meta = self.meta @@ -31,17 +32,18 @@ def as_json protected - attr_reader :object, :scope, :data, :options, :links, :meta + attr_reader :object, :scope, :data, :serializable_resource_options, + :association_options, :links, :meta private - def data_for(serializer, options) + def data_for(serializer) if serializer.respond_to?(:each) - serializer.map { |s| ResourceIdentifier.new(s).as_json } - elsif options[:virtual_value] - options[:virtual_value] + serializer.map { |s| ResourceIdentifier.new(s, serializable_resource_options).as_json } + elsif association_options[:virtual_value] + association_options[:virtual_value] elsif serializer && serializer.object - ResourceIdentifier.new(serializer).as_json + ResourceIdentifier.new(serializer, serializable_resource_options).as_json end end end diff --git a/lib/active_model_serializers/adapter/json_api/resource_identifier.rb b/lib/active_model_serializers/adapter/json_api/resource_identifier.rb index 3affb03a8..4d07d11c9 100644 --- a/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +++ b/lib/active_model_serializers/adapter/json_api/resource_identifier.rb @@ -3,9 +3,10 @@ module Adapter class JsonApi class ResourceIdentifier # {http://jsonapi.org/format/#document-resource-identifier-objects Resource Identifier Objects} - def initialize(serializer) + def initialize(serializer, options) @id = id_for(serializer) - @type = type_for(serializer) + @type = JsonApi.send(:transform_key_casing!, type_for(serializer), + options) end def as_json diff --git a/lib/active_model_serializers/key_transform.rb b/lib/active_model_serializers/key_transform.rb index cf1205479..c3eee97bc 100644 --- a/lib/active_model_serializers/key_transform.rb +++ b/lib/active_model_serializers/key_transform.rb @@ -4,47 +4,67 @@ module ActiveModelSerializers module KeyTransform module_function - # Transforms keys to UpperCamelCase or PascalCase. + # Transforms values to UpperCamelCase or PascalCase. # # @example: # "some_key" => "SomeKey", # @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L66-L76 ActiveSupport::Inflector.camelize} - def camel(hash) - hash.deep_transform_keys! { |key| key.to_s.camelize.to_sym } + def camel(value) + case value + when Hash then value.deep_transform_keys! { |key| camel(key) } + when Symbol then camel(value.to_s).to_sym + when String then value.camelize + else value + end end - # Transforms keys to camelCase. + # Transforms values to camelCase. # # @example: # "some_key" => "someKey", # @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L66-L76 ActiveSupport::Inflector.camelize} - def camel_lower(hash) - hash.deep_transform_keys! { |key| key.to_s.camelize(:lower).to_sym } + def camel_lower(value) + case value + when Hash then value.deep_transform_keys! { |key| camel_lower(key) } + when Symbol then camel_lower(value.to_s).to_sym + when String then value.camelize(:lower) + else value + end end - # Transforms keys to dashed-case. + # Transforms values to dashed-case. # This is the default case for the JsonApi adapter. # # @example: # "some_key" => "some-key", # @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L185-L187 ActiveSupport::Inflector.dasherize} - def dashed(hash) - hash.deep_transform_keys! { |key| key.to_s.dasherize.to_sym } + def dash(value) + case value + when Hash then value.deep_transform_keys! { |key| dash(key) } + when Symbol then dash(value.to_s).to_sym + when String then value.dasherize + else value + end end - # Transforms keys to underscore. + # Transforms values to underscore_case. # This is the default case for deserialization in the JsonApi adapter. # # @example: # "some-key" => "some_key", # @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L89-L98 ActiveSupport::Inflector.underscore} - def underscore(hash) - hash.deep_transform_keys! { |key| key.to_s.underscore.to_sym } + def underscore(value) + case value + when Hash then value.deep_transform_keys! { |key| underscore(key) } + when Symbol then underscore(value.to_s).to_sym + when String then value.underscore + else value + end end - # Returns the hash unaltered - def unaltered(hash) - hash + # Returns the value unaltered + def unaltered(value) + value end end end diff --git a/lib/active_model_serializers/serialization_context.rb b/lib/active_model_serializers/serialization_context.rb index 498eaa68a..c61a43b94 100644 --- a/lib/active_model_serializers/serialization_context.rb +++ b/lib/active_model_serializers/serialization_context.rb @@ -27,7 +27,6 @@ def initialize(request, options = {}) @query_parameters = request.query_parameters @url_helpers = options.delete(:url_helpers) || self.class.url_helpers @default_url_options = options.delete(:default_url_options) || self.class.default_url_options - @key_transform = options.delete(:key_transform) end end end diff --git a/test/action_controller/json_api/key_transform_test.rb b/test/action_controller/json_api/transform_test.rb similarity index 75% rename from test/action_controller/json_api/key_transform_test.rb rename to test/action_controller/json_api/transform_test.rb index 63d9a8974..ec283ab88 100644 --- a/test/action_controller/json_api/key_transform_test.rb +++ b/test/action_controller/json_api/transform_test.rb @@ -10,7 +10,7 @@ class PostSerializer < ActiveModel::Serializer type 'posts' attributes :title, :body, :publish_at belongs_to :author - has_many :comments + has_many :top_comments link(:post_authors) { 'https://example.com/post_authors' } @@ -28,9 +28,9 @@ class AuthorSerializer < ActiveModel::Serializer attributes :first_name, :last_name end - Comment = Class.new(::Model) - class CommentSerializer < ActiveModel::Serializer - type 'comments' + TopComment = Class.new(::Model) + class TopCommentSerializer < ActiveModel::Serializer + type 'top_comments' attributes :body belongs_to :author end @@ -38,28 +38,28 @@ class CommentSerializer < ActiveModel::Serializer def setup_post ActionController::Base.cache_store.clear @author = Author.new(id: 1, first_name: 'Bob', last_name: 'Jones') - @comment1 = Comment.new(id: 7, body: 'cool', author: @author) - @comment2 = Comment.new(id: 12, body: 'awesome', author: @author) + @comment1 = TopComment.new(id: 7, body: 'cool', author: @author) + @comment2 = TopComment.new(id: 12, body: 'awesome', author: @author) @post = Post.new(id: 1337, title: 'Title 1', body: 'Body 1', - author: @author, comments: [@comment1, @comment2], + author: @author, top_comments: [@comment1, @comment2], publish_at: '2020-03-16T03:55:25.291Z') @comment1.post = @post @comment2.post = @post end - def render_resource_with_key_transform + def render_resource_with_transform setup_post render json: @post, serializer: PostSerializer, adapter: :json_api, key_transform: :camel end - def render_resource_with_key_transform_nil + def render_resource_with_transform_nil setup_post render json: @post, serializer: PostSerializer, adapter: :json_api, key_transform: nil end - def render_resource_with_key_transform_with_global_config + def render_resource_with_transform_with_global_config setup_post old_transform = ActiveModelSerializers.config.key_transform ActiveModelSerializers.config.key_transform = :camel_lower @@ -70,13 +70,13 @@ def render_resource_with_key_transform_with_global_config tests KeyTransformTestController - def test_render_resource_with_key_transform - get :render_resource_with_key_transform + def test_render_resource_with_transform + get :render_resource_with_transform response = JSON.parse(@response.body) expected = { 'Data' => { 'Id' => '1337', - 'Type' => 'posts', + 'Type' => 'Posts', 'Attributes' => { 'Title' => 'Title 1', 'Body' => 'Body 1', @@ -86,13 +86,13 @@ def test_render_resource_with_key_transform 'Author' => { 'Data' => { 'Id' => '1', - 'Type' => 'authors' + 'Type' => 'Authors' } }, - 'Comments' => { + 'TopComments' => { 'Data' => [ - { 'Id' => '7', 'Type' => 'comments' }, - { 'Id' => '12', 'Type' => 'comments' } + { 'Id' => '7', 'Type' => 'TopComments' }, + { 'Id' => '12', 'Type' => 'TopComments' } ] } }, @@ -105,8 +105,8 @@ def test_render_resource_with_key_transform assert_equal expected, response end - def test_render_resource_with_key_transform_nil - get :render_resource_with_key_transform_nil + def test_render_resource_with_transform_nil + get :render_resource_with_transform_nil response = JSON.parse(@response.body) expected = { 'data' => { @@ -124,10 +124,10 @@ def test_render_resource_with_key_transform_nil 'type' => 'authors' } }, - 'comments' => { + 'top-comments' => { 'data' => [ - { 'id' => '7', 'type' => 'comments' }, - { 'id' => '12', 'type' => 'comments' } + { 'id' => '7', 'type' => 'top-comments' }, + { 'id' => '12', 'type' => 'top-comments' } ] } }, @@ -140,8 +140,8 @@ def test_render_resource_with_key_transform_nil assert_equal expected, response end - def test_render_resource_with_key_transform_with_global_config - get :render_resource_with_key_transform_with_global_config + def test_render_resource_with_transform_with_global_config + get :render_resource_with_transform_with_global_config response = JSON.parse(@response.body) expected = { 'data' => { @@ -159,10 +159,10 @@ def test_render_resource_with_key_transform_with_global_config 'type' => 'authors' } }, - 'comments' => { + 'topComments' => { 'data' => [ - { 'id' => '7', 'type' => 'comments' }, - { 'id' => '12', 'type' => 'comments' } + { 'id' => '7', 'type' => 'topComments' }, + { 'id' => '12', 'type' => 'topComments' } ] } }, diff --git a/test/active_model_serializers/key_transform_test.rb b/test/active_model_serializers/key_transform_test.rb new file mode 100644 index 000000000..b85a9e4c4 --- /dev/null +++ b/test/active_model_serializers/key_transform_test.rb @@ -0,0 +1,123 @@ +require 'test_helper' + +class ActiveModelSerializers::KeyTransformTest < ActiveSupport::TestCase + def test_camel + obj = Object.new + scenarios = [ + { + value: { :some_key => 'value' }, + expected: { :SomeKey => 'value' } + }, + { + value: { 'some_key' => 'value' }, + expected: { 'SomeKey' => 'value' } + }, + { + value: :some_value, + expected: :SomeValue + }, + { + value: obj, + expected: obj + }, + { + value: nil, + expected: nil + } + ] + scenarios.each do |s| + result = ActiveModelSerializers::KeyTransform.camel(s[:value]) + assert_equal s[:expected], result + end + end + + def test_camel_lower + obj = Object.new + scenarios = [ + { + value: { :some_key => 'value' }, + expected: { :someKey => 'value' } + }, + { + value: { 'some_key' => 'value' }, + expected: { 'someKey' => 'value' } + }, + { + value: :some_value, + expected: :someValue + }, + { + value: obj, + expected: obj + }, + { + value: nil, + expected: nil + } + ] + scenarios.each do |s| + result = ActiveModelSerializers::KeyTransform.camel_lower(s[:value]) + assert_equal s[:expected], result + end + end + + def test_dash + obj = Object.new + scenarios = [ + { + value: { :some_key => 'value' }, + expected: { :"some-key" => 'value' } + }, + { + value: { 'some_key' => 'value' }, + expected: { 'some-key' => 'value' } + }, + { + value: :some_value, + expected: :"some-value" + }, + { + value: obj, + expected: obj + }, + { + value: nil, + expected: nil + } + ] + scenarios.each do |s| + result = ActiveModelSerializers::KeyTransform.dash(s[:value]) + assert_equal s[:expected], result + end + end + + def test_underscore + obj = Object.new + scenarios = [ + { + value: { :"some-key" => 'value' }, + expected: { :some_key => 'value' } + }, + { + value: { 'some-key' => 'value' }, + expected: { 'some_key' => 'value' } + }, + { + value: :"some-value", + expected: :some_value + }, + { + value: obj, + expected: obj + }, + { + value: nil, + expected: nil + } + ] + scenarios.each do |s| + result = ActiveModelSerializers::KeyTransform.underscore(s[:value]) + assert_equal s[:expected], result + end + end +end diff --git a/test/adapter/json/key_case_test.rb b/test/adapter/json/transform_test.rb similarity index 85% rename from test/adapter/json/key_case_test.rb rename to test/adapter/json/transform_test.rb index 17219f3c6..30e058a50 100644 --- a/test/adapter/json/key_case_test.rb +++ b/test/adapter/json/transform_test.rb @@ -8,8 +8,8 @@ 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) @options = {} + @options[:key_transform] = key_transform if key_transform @options[:serialization_context] = context end @@ -25,14 +25,14 @@ def setup @adapter = ActiveModelSerializers::Adapter::Json.new(serializer) end - def test_key_transform_default + def test_transform_default mock_request assert_equal({ blog: { id: 1, special_attribute: 'neat', articles: nil } }, @adapter.serializable_hash(@options)) end - def test_key_transform_global_config + def test_transform_global_config mock_request result = with_config(key_transform: :camel_lower) do @adapter.serializable_hash(@options) @@ -42,7 +42,7 @@ def test_key_transform_global_config }, result) end - def test_key_transform_serialization_ctx_overrides_global_config + def test_transform_serialization_ctx_overrides_global_config mock_request(:camel) result = with_config(key_transform: :camel_lower) do @adapter.serializable_hash(@options) @@ -52,7 +52,7 @@ def test_key_transform_serialization_ctx_overrides_global_config }, result) end - def test_key_transform_undefined + def test_transform_undefined mock_request(:blam) result = nil assert_raises NoMethodError do @@ -60,28 +60,28 @@ def test_key_transform_undefined end end - def test_key_transform_dashed - mock_request(:dashed) + def test_transform_dash + mock_request(:dash) assert_equal({ blog: { id: 1, :"special-attribute" => 'neat', articles: nil } }, @adapter.serializable_hash(@options)) end - def test_key_transform_unaltered + def test_transform_unaltered mock_request(:unaltered) assert_equal({ blog: { id: 1, special_attribute: 'neat', articles: nil } }, @adapter.serializable_hash(@options)) end - def test_key_transform_camel + def test_transform_camel mock_request(:camel) assert_equal({ Blog: { Id: 1, SpecialAttribute: 'neat', Articles: nil } }, @adapter.serializable_hash(@options)) end - def test_key_transform_camel_lower + def test_transform_camel_lower mock_request(:camel_lower) assert_equal({ blog: { id: 1, specialAttribute: 'neat', articles: nil } diff --git a/test/adapter/json_api/has_many_test.rb b/test/adapter/json_api/has_many_test.rb index d590b8dfd..4c391eb43 100644 --- a/test/adapter/json_api/has_many_test.rb +++ b/test/adapter/json_api/has_many_test.rb @@ -129,7 +129,7 @@ def test_has_many_with_virtual_value assert_equal({ data: { id: '1', - type: 'virtual_values', + type: 'virtual-values', relationships: { maker: { data: { id: 1 } }, reviews: { data: [{ id: 1 }, { id: 2 }] } diff --git a/test/adapter/json_api/has_one_test.rb b/test/adapter/json_api/has_one_test.rb index b346dcd08..e0ea4cd76 100644 --- a/test/adapter/json_api/has_one_test.rb +++ b/test/adapter/json_api/has_one_test.rb @@ -63,7 +63,7 @@ def test_has_one_with_virtual_value expected = { data: { id: '1', - type: 'virtual_values', + type: 'virtual-values', relationships: { maker: { data: { id: 1 } }, reviews: { data: [{ id: 1 }, { id: 2 }] } diff --git a/test/adapter/json_api/linked_test.rb b/test/adapter/json_api/linked_test.rb index 03fb3504d..02ca27d77 100644 --- a/test/adapter/json_api/linked_test.rb +++ b/test/adapter/json_api/linked_test.rb @@ -216,7 +216,7 @@ def test_underscore_model_namespace_for_linked_resource_type expected = { related: { data: [{ - type: 'spam_unrelated_links', + type: 'spam-unrelated-links', id: '456' }] } @@ -366,12 +366,12 @@ def test_no_duplicates_global adapter: :json_api, include: '*').serializable_hash expected = [ - type: 'nested_posts', id: '2', + type: 'nested-posts', id: '2', relationships: { - nested_posts: { + :"nested-posts" => { data: [ - { type: 'nested_posts', id: '1' }, - { type: 'nested_posts', id: '2' } + { type: 'nested-posts', id: '1' }, + { type: 'nested-posts', id: '2' } ] } } diff --git a/test/adapter/json_api/links_test.rb b/test/adapter/json_api/links_test.rb index b56611978..8f26f34a2 100644 --- a/test/adapter/json_api/links_test.rb +++ b/test/adapter/json_api/links_test.rb @@ -80,10 +80,10 @@ def test_resource_links } }, author: 'http://example.com/link_authors/1337', - link_authors: 'http://example.com/link_authors', + :"link-authors" => 'http://example.com/link_authors', resource: 'http://example.com/resource', posts: 'http://example.com/link_authors/1337/posts', - yet_another: 'http://example.com/resource/1337' + :"yet-another" => 'http://example.com/resource/1337' } assert_equal(expected, hash[:data][:links]) end diff --git a/test/adapter/json_api/pagination_links_test.rb b/test/adapter/json_api/pagination_links_test.rb index 5de78fe2b..244f8108c 100644 --- a/test/adapter/json_api/pagination_links_test.rb +++ b/test/adapter/json_api/pagination_links_test.rb @@ -25,7 +25,6 @@ def mock_request(query_parameters = {}, original_url = URI) context = Minitest::Mock.new context.expect(:request_url, original_url) context.expect(:query_parameters, query_parameters) - context.expect(:key_transform, nil) @options = {} @options[:serialization_context] = context end diff --git a/test/adapter/json_api/relationship_test.rb b/test/adapter/json_api/relationship_test.rb index bb3dbcb74..1708d5f3b 100644 --- a/test/adapter/json_api/relationship_test.rb +++ b/test/adapter/json_api/relationship_test.rb @@ -151,11 +151,8 @@ def test_relationship_with_everything private def test_relationship(expected, params = {}) - options = params.fetch(:options, {}) - links = params.fetch(:links, {}) - meta = params[:meta] parent_serializer = AuthorSerializer.new(@author) - relationship = Relationship.new(parent_serializer, @serializer, options, links, meta) + relationship = Relationship.new(parent_serializer, @serializer, nil, params) assert_equal(expected, relationship.as_json) end end diff --git a/test/adapter/json_api/resource_identifier_test.rb b/test/adapter/json_api/resource_identifier_test.rb index 513b6affb..a6f312c43 100644 --- a/test/adapter/json_api/resource_identifier_test.rb +++ b/test/adapter/json_api/resource_identifier_test.rb @@ -22,7 +22,7 @@ class FragmentedSerializer < ActiveModel::Serializer; end end def test_defined_type - test_type(WithDefinedTypeSerializer, 'with_defined_type') + test_type(WithDefinedTypeSerializer, 'with-defined-type') end def test_singular_type @@ -58,7 +58,7 @@ def test_type_inflection(serializer_class, expected_type, inflection) def test_type(serializer_class, expected_type) serializer = serializer_class.new(@model) - resource_identifier = ResourceIdentifier.new(serializer) + resource_identifier = ResourceIdentifier.new(serializer, nil) expected = { id: @model.id.to_s, type: expected_type @@ -69,7 +69,7 @@ def test_type(serializer_class, expected_type) def test_id(serializer_class, id) serializer = serializer_class.new(@model) - resource_identifier = ResourceIdentifier.new(serializer) + resource_identifier = ResourceIdentifier.new(serializer, nil) inflection = ActiveModelSerializers.config.jsonapi_resource_type type = @model.class.model_name.send(inflection) expected = { diff --git a/test/adapter/json_api/resource_meta_test.rb b/test/adapter/json_api/resource_meta_test.rb index c29e9af20..5b58db9ff 100644 --- a/test/adapter/json_api/resource_meta_test.rb +++ b/test/adapter/json_api/resource_meta_test.rb @@ -54,7 +54,7 @@ def test_meta_block_object_resource adapter: :json_api ).serializable_hash expected = { - comments_count: @post.comments.count + :"comments-count" => @post.comments.count } assert_equal(expected, hash[:data][:meta]) end @@ -69,8 +69,8 @@ def test_meta_object_resource_in_array ).serializable_hash expected = { :data => [ - { :id => '1337', :type => 'posts', :meta => { :comments_count => 0 } }, - { :id => '1339', :type => 'posts', :meta => { :comments_count => 1 } } + { :id => '1337', :type => 'posts', :meta => { :"comments-count" => 0 } }, + { :id => '1339', :type => 'posts', :meta => { :"comments-count" => 1 } } ] } assert_equal(expected, hash) diff --git a/test/adapter/json_api/key_case_test.rb b/test/adapter/json_api/transform_test.rb similarity index 88% rename from test/adapter/json_api/key_case_test.rb rename to test/adapter/json_api/transform_test.rb index 910769604..856110870 100644 --- a/test/adapter/json_api/key_case_test.rb +++ b/test/adapter/json_api/transform_test.rb @@ -36,13 +36,13 @@ class CommentSerializer < ActiveModel::Serializer belongs_to :author end - def mock_request(key_transform = nil) + def mock_request(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[:key_transform] = transform if transform @options[:serialization_context] = context end @@ -64,7 +64,7 @@ def setup @comment2.post = @post end - def test_success_document_key_transform_default + def test_success_document_transform_default mock_request serializer = PostSerializer.new(@post) adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) @@ -98,7 +98,7 @@ def test_success_document_key_transform_default }, result) end - def test_success_document_key_transform_global_config + def test_success_document_transform_global_config mock_request result = with_config(key_transform: :camel_lower) do serializer = PostSerializer.new(@post) @@ -134,7 +134,7 @@ def test_success_document_key_transform_global_config }, result) end - def test_success_doc_key_transform_serialization_ctx_overrides_global + def test_success_doc_transform_serialization_ctx_overrides_global mock_request(:camel) result = with_config(key_transform: :camel_lower) do serializer = PostSerializer.new(@post) @@ -144,7 +144,7 @@ def test_success_doc_key_transform_serialization_ctx_overrides_global assert_equal({ Data: { Id: '1337', - Type: 'posts', + Type: 'Posts', Attributes: { Title: 'Title 1', Body: 'Body 1', @@ -152,12 +152,12 @@ def test_success_doc_key_transform_serialization_ctx_overrides_global }, Relationships: { Author: { - Data: { Id: '1', Type: 'authors' } + Data: { Id: '1', Type: 'Authors' } }, Comments: { Data: [ - { Id: '7', Type: 'comments' }, - { Id: '12', Type: 'comments' } + { Id: '7', Type: 'Comments' }, + { Id: '12', Type: 'Comments' } ] } }, Links: { @@ -170,8 +170,8 @@ def test_success_doc_key_transform_serialization_ctx_overrides_global }, result) end - def test_success_document_key_transform_dashed - mock_request(:dashed) + def test_success_document_transform_dash + mock_request(:dash) serializer = PostSerializer.new(@post) adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) result = adapter.serializable_hash(@options) @@ -204,7 +204,7 @@ def test_success_document_key_transform_dashed }, result) end - def test_success_document_key_transform_unaltered + def test_success_document_transform_unaltered mock_request(:unaltered) serializer = PostSerializer.new(@post) adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) @@ -238,7 +238,7 @@ def test_success_document_key_transform_unaltered }, result) end - def test_success_document_key_transform_undefined + def test_success_document_transform_undefined mock_request(:zoot) serializer = PostSerializer.new(@post) adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) @@ -247,7 +247,7 @@ def test_success_document_key_transform_undefined end end - def test_success_document_key_transform_camel + def test_success_document_transform_camel mock_request(:camel) serializer = PostSerializer.new(@post) adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) @@ -255,7 +255,7 @@ def test_success_document_key_transform_camel assert_equal({ Data: { Id: '1337', - Type: 'posts', + Type: 'Posts', Attributes: { Title: 'Title 1', Body: 'Body 1', @@ -263,12 +263,12 @@ def test_success_document_key_transform_camel }, Relationships: { Author: { - Data: { Id: '1', Type: 'authors' } + Data: { Id: '1', Type: 'Authors' } }, Comments: { Data: [ - { Id: '7', Type: 'comments' }, - { Id: '12', Type: 'comments' } + { Id: '7', Type: 'Comments' }, + { Id: '12', Type: 'Comments' } ] } }, Links: { @@ -281,7 +281,7 @@ def test_success_document_key_transform_camel }, result) end - def test_success_document_key_transform_camel_lower + def test_success_document_transform_camel_lower mock_request(:camel_lower) serializer = PostSerializer.new(@post) adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) @@ -315,7 +315,7 @@ def test_success_document_key_transform_camel_lower }, result) end - def test_error_document_key_transform_default + def test_error_document_transform_default mock_request resource = ModelWithErrors.new resource.errors.add(:published_at, 'must be in the future') @@ -327,7 +327,7 @@ def test_error_document_key_transform_default { :errors => [ { - :source => { :pointer => '/data/attributes/published_at' }, + :source => { :pointer => '/data/attributes/published-at' }, :detail => 'must be in the future' }, { :source => { :pointer => '/data/attributes/title' }, @@ -338,7 +338,7 @@ def test_error_document_key_transform_default assert_equal expected_errors_object, result end - def test_error_document_key_transform_global_config + def test_error_document_transform_global_config mock_request result = with_config(key_transform: :camel) do resource = ModelWithErrors.new @@ -352,11 +352,11 @@ def test_error_document_key_transform_global_config { :Errors => [ { - :Source => { :Pointer => '/data/attributes/published_at' }, + :Source => { :Pointer => '/data/attributes/PublishedAt' }, :Detail => 'must be in the future' }, { - :Source => { :Pointer => '/data/attributes/title' }, + :Source => { :Pointer => '/data/attributes/Title' }, :Detail => 'must be longer' } ] @@ -364,7 +364,7 @@ def test_error_document_key_transform_global_config assert_equal expected_errors_object, result end - def test_error_document_key_transform_serialization_ctx_overrides_global + def test_error_document_transform_serialization_ctx_overrides_global mock_request(:camel) result = with_config(key_transform: :camel_lower) do resource = ModelWithErrors.new @@ -378,11 +378,11 @@ def test_error_document_key_transform_serialization_ctx_overrides_global { :Errors => [ { - :Source => { :Pointer => '/data/attributes/published_at' }, + :Source => { :Pointer => '/data/attributes/PublishedAt' }, :Detail => 'must be in the future' }, { - :Source => { :Pointer => '/data/attributes/title' }, + :Source => { :Pointer => '/data/attributes/Title' }, :Detail => 'must be longer' } ] @@ -390,8 +390,8 @@ def test_error_document_key_transform_serialization_ctx_overrides_global assert_equal expected_errors_object, result end - def test_error_document_key_transform_dashed - mock_request(:dashed) + def test_error_document_transform_dash + mock_request(:dash) resource = ModelWithErrors.new resource.errors.add(:published_at, 'must be in the future') @@ -405,7 +405,7 @@ def test_error_document_key_transform_dashed { :errors => [ { - :source => { :pointer => '/data/attributes/published_at' }, + :source => { :pointer => '/data/attributes/published-at' }, :detail => 'must be in the future' }, { @@ -417,7 +417,7 @@ def test_error_document_key_transform_dashed assert_equal expected_errors_object, result end - def test_error_document_key_transform_unaltered + def test_error_document_transform_unaltered mock_request(:unaltered) resource = ModelWithErrors.new @@ -438,7 +438,7 @@ def test_error_document_key_transform_unaltered assert_equal expected_errors_object, result end - def test_error_document_key_transform_undefined + def test_error_document_transform_undefined mock_request(:krazy) resource = ModelWithErrors.new @@ -453,7 +453,7 @@ def test_error_document_key_transform_undefined end end - def test_error_document_key_transform_camel + def test_error_document_transform_camel mock_request(:camel) resource = ModelWithErrors.new @@ -467,14 +467,14 @@ def test_error_document_key_transform_camel 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/PublishedAt' }, :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 + def test_error_document_transform_camel_lower mock_request(:camel_lower) resource = ModelWithErrors.new @@ -488,7 +488,7 @@ def test_error_document_key_transform_camel_lower expected_errors_object = { :errors => [ - { :source => { :pointer => '/data/attributes/published_at' }, :detail => 'must be in the future' }, + { :source => { :pointer => '/data/attributes/publishedAt' }, :detail => 'must be in the future' }, { :source => { :pointer => '/data/attributes/title' }, :detail => 'must be longer' } ] } diff --git a/test/benchmark/bm_caching.rb b/test/benchmark/bm_caching.rb index ac866e7e4..c2abbc659 100644 --- a/test/benchmark/bm_caching.rb +++ b/test/benchmark/bm_caching.rb @@ -70,7 +70,8 @@ def expected }, 'author' => { 'id' => 42, - 'name' => 'Joao Moura.' + 'first_name' => 'Joao', + 'last_name' => 'Moura' } } } diff --git a/test/benchmark/bm_transform.rb b/test/benchmark/bm_transform.rb new file mode 100644 index 000000000..b1703712c --- /dev/null +++ b/test/benchmark/bm_transform.rb @@ -0,0 +1,34 @@ +require_relative './benchmarking_support' +require_relative './app' + +time = 10 +disable_gc = true +ActiveModelSerializers.config.key_transform = :unaltered +comments = (0..50).map do |i| + Comment.new(id: i, body: 'ZOMG A COMMENT') +end +author = Author.new(id: 42, first_name: 'Joao', last_name: 'Moura') +post = Post.new(id: 1337, title: 'New Post', blog: nil, body: 'Body', comments: comments, author: author) +serializer = PostSerializer.new(post) +adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer) +serialization = adapter.as_json + +Benchmark.ams('camel', time: time, disable_gc: disable_gc) do + ActiveModelSerializers::KeyTransform.camel(serialization) +end + +Benchmark.ams('camel_lower', time: time, disable_gc: disable_gc) do + ActiveModelSerializers::KeyTransform.camel_lower(serialization) +end + +Benchmark.ams('dash', time: time, disable_gc: disable_gc) do + ActiveModelSerializers::KeyTransform.dash(serialization) +end + +Benchmark.ams('unaltered', time: time, disable_gc: disable_gc) do + ActiveModelSerializers::KeyTransform.unaltered(serialization) +end + +Benchmark.ams('underscore', time: time, disable_gc: disable_gc) do + ActiveModelSerializers::KeyTransform.underscore(serialization) +end diff --git a/test/benchmark/controllers.rb b/test/benchmark/controllers.rb index 9d7934e5d..e95ab11af 100644 --- a/test/benchmark/controllers.rb +++ b/test/benchmark/controllers.rb @@ -8,7 +8,7 @@ class PostController < ActionController::Base else comments = [Comment.new(id: 1, body: 'ZOMG A COMMENT')] end - author = Author.new(id: 42, name: 'Joao Moura.') + author = Author.new(id: 42, first_name: 'Joao', last_name: 'Moura') Post.new(id: 1337, title: 'New Post', blog: nil, body: 'Body', comments: comments, author: author) end diff --git a/test/benchmark/fixtures.rb b/test/benchmark/fixtures.rb index bdba919b1..039adb023 100644 --- a/test/benchmark/fixtures.rb +++ b/test/benchmark/fixtures.rb @@ -1,6 +1,6 @@ Rails.configuration.serializers = [] class AuthorSerializer < ActiveModel::Serializer - attributes :id, :name + attributes :id, :first_name, :last_name has_many :posts, embed: :ids has_one :bio @@ -27,6 +27,15 @@ class PostSerializer < ActiveModel::Serializer belongs_to :blog, serializer: BlogSerializer belongs_to :author, serializer: AuthorSerializer + link(:post_authors) { 'https://example.com/post_authors' } + + meta do + { + rating: 5, + favorite_count: 10 + } + end + def blog Blog.new(id: 999, name: 'Custom blog') end @@ -34,7 +43,7 @@ def blog Rails.configuration.serializers << PostSerializer class CachingAuthorSerializer < AuthorSerializer - cache key: 'writer', only: [:name], skip_digest: true + cache key: 'writer', only: [:first_name, :last_name], skip_digest: true end Rails.configuration.serializers << CachingAuthorSerializer @@ -63,7 +72,8 @@ class CachingPostSerializer < PostSerializer t.timestamps null: false end create_table :authors, force: true do |t| - t.string :name + t.string :first_name + t.string :last_name t.timestamps null: false end create_table :posts, force: true do |t| @@ -144,7 +154,7 @@ class Comment < BenchmarkModel end class Author < BenchmarkModel - attr_accessor :id, :name, :posts + attr_accessor :id, :first_name, :last_name, :posts end class Post < BenchmarkModel