Support key transformation for Attributes adapter (#1889)

The `:attributes` adapter is the default one, but it did not support
key transformation. This was very surprising behavior, since the
"Configuration Options" page in the guides didn't mention that this
behavior was not supported by the attributes adapter.

This commit adds key transform support to the attributes adapter, and
adds documentation about the default transform for the attributes
adapter (which is `:unaltered`).

This commit also handles arrays when transforming keys, which was needed
in the case where you're serializing a collection with the Attributes
adapter. With the JSON adapter, it was always guaranteed to pass a hash
to the KeyTransform functions because of the top-level key. Since there
is no top-level key for the Attributes adapter, the return value could
be an array.
This commit is contained in:
Ian C. Anderson 2016-08-25 15:21:27 -04:00 committed by L. Preston Sego III
parent 49ee823a53
commit 2423ca4999
6 changed files with 84 additions and 1 deletions

View File

@ -8,6 +8,7 @@ Features:
- [#1791](https://github.com/rails-api/active_model_serializers/pull/1791) (@bf4, @youroff, @NullVoxPopuli) - [#1791](https://github.com/rails-api/active_model_serializers/pull/1791) (@bf4, @youroff, @NullVoxPopuli)
- Added `jsonapi_namespace_separator` config option. - Added `jsonapi_namespace_separator` config option.
- [#1889](https://github.com/rails-api/active_model_serializers/pull/1889) Support key transformation for Attributes adapter (@iancanderson, @danbee)
Fixes: Fixes:

View File

@ -46,6 +46,7 @@ Each adapter has a default key transform configured:
| Adapter | Default Key Transform | | Adapter | Default Key Transform |
|----|----| |----|----|
| `Attributes` | `:unaltered` |
| `Json` | `:unaltered` | | `Json` | `:unaltered` |
| `JsonApi` | `:dash` | | `JsonApi` | `:dash` |

View File

@ -4,7 +4,9 @@ module ActiveModelSerializers
def serializable_hash(options = nil) def serializable_hash(options = nil)
options = serialization_options(options) options = serialization_options(options)
options[:fields] ||= instance_options[:fields] options[:fields] ||= instance_options[:fields]
serializer.serializable_hash(instance_options, options, self) serialized_hash = serializer.serializable_hash(instance_options, options, self)
self.class.transform_key_casing!(serialized_hash, instance_options)
end end
end end
end end

View File

@ -11,6 +11,7 @@ module ActiveModelSerializers
# @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L66-L76 ActiveSupport::Inflector.camelize} # @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L66-L76 ActiveSupport::Inflector.camelize}
def camel(value) def camel(value)
case value case value
when Array then value.map { |item| camel(item) }
when Hash then value.deep_transform_keys! { |key| camel(key) } when Hash then value.deep_transform_keys! { |key| camel(key) }
when Symbol then camel(value.to_s).to_sym when Symbol then camel(value.to_s).to_sym
when String then value.underscore.camelize when String then value.underscore.camelize
@ -25,6 +26,7 @@ module ActiveModelSerializers
# @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L66-L76 ActiveSupport::Inflector.camelize} # @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L66-L76 ActiveSupport::Inflector.camelize}
def camel_lower(value) def camel_lower(value)
case value case value
when Array then value.map { |item| camel_lower(item) }
when Hash then value.deep_transform_keys! { |key| camel_lower(key) } when Hash then value.deep_transform_keys! { |key| camel_lower(key) }
when Symbol then camel_lower(value.to_s).to_sym when Symbol then camel_lower(value.to_s).to_sym
when String then value.underscore.camelize(:lower) when String then value.underscore.camelize(:lower)
@ -40,6 +42,7 @@ module ActiveModelSerializers
# @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L185-L187 ActiveSupport::Inflector.dasherize} # @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L185-L187 ActiveSupport::Inflector.dasherize}
def dash(value) def dash(value)
case value case value
when Array then value.map { |item| dash(item) }
when Hash then value.deep_transform_keys! { |key| dash(key) } when Hash then value.deep_transform_keys! { |key| dash(key) }
when Symbol then dash(value.to_s).to_sym when Symbol then dash(value.to_s).to_sym
when String then value.underscore.dasherize when String then value.underscore.dasherize
@ -55,6 +58,7 @@ module ActiveModelSerializers
# @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L89-L98 ActiveSupport::Inflector.underscore} # @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L89-L98 ActiveSupport::Inflector.underscore}
def underscore(value) def underscore(value)
case value case value
when Array then value.map { |item| underscore(item) }
when Hash then value.deep_transform_keys! { |key| underscore(key) } when Hash then value.deep_transform_keys! { |key| underscore(key) }
when Symbol then underscore(value.to_s).to_sym when Symbol then underscore(value.to_s).to_sym
when String then value.underscore when String then value.underscore

View File

@ -60,6 +60,14 @@ module ActiveModelSerializers
{ {
value: nil, value: nil,
expected: nil expected: nil
},
{
value: [
{ some_value: 'value' }
],
expected: [
{ SomeValue: 'value' }
]
} }
] ]
scenarios.each do |s| scenarios.each do |s|
@ -126,6 +134,14 @@ module ActiveModelSerializers
{ {
value: nil, value: nil,
expected: nil expected: nil
},
{
value: [
{ some_value: 'value' }
],
expected: [
{ someValue: 'value' }
]
} }
] ]
scenarios.each do |s| scenarios.each do |s|
@ -188,6 +204,14 @@ module ActiveModelSerializers
{ {
value: nil, value: nil,
expected: nil expected: nil
},
{
value: [
{ 'some_value' => 'value' }
],
expected: [
{ 'some-value' => 'value' }
]
} }
] ]
scenarios.each do |s| scenarios.each do |s|
@ -254,6 +278,14 @@ module ActiveModelSerializers
{ {
value: nil, value: nil,
expected: nil expected: nil
},
{
value: [
{ 'some-value' => 'value' }
],
expected: [
{ 'some_value' => 'value' }
]
} }
] ]
scenarios.each do |s| scenarios.each do |s|

View File

@ -0,0 +1,43 @@
require 'test_helper'
module ActiveModelSerializers
module Adapter
class AttributesTest < ActiveSupport::TestCase
class Person
include ActiveModel::Model
include ActiveModel::Serialization
attr_accessor :first_name, :last_name
end
class PersonSerializer < ActiveModel::Serializer
attributes :first_name, :last_name
end
def setup
ActionController::Base.cache_store.clear
end
def test_serializable_hash
person = Person.new(first_name: 'Arthur', last_name: 'Dent')
serializer = PersonSerializer.new(person)
adapter = ActiveModelSerializers::Adapter::Attributes.new(serializer)
assert_equal({ first_name: 'Arthur', last_name: 'Dent' },
adapter.serializable_hash)
end
def test_serializable_hash_with_transform_key_casing
person = Person.new(first_name: 'Arthur', last_name: 'Dent')
serializer = PersonSerializer.new(person)
adapter = ActiveModelSerializers::Adapter::Attributes.new(
serializer,
key_transform: :camel_lower
)
assert_equal({ firstName: 'Arthur', lastName: 'Dent' },
adapter.serializable_hash)
end
end
end
end