Properly deserialize dasherized keys

The JSON API adapater dasherizes every key, but the deserializer left the keys
unaltered. Thus, the client had to send underscored keys in the request body in
order for Rails to properly match sent values to model attributes.

This commit adds automatic key transformation on deserialization. Per default the
deserializer transforms the keys to underscore, but this behaviour can also be
changed by including `key_transform` in the deserializer options.
This commit is contained in:
Moritz Lawitschka 2016-03-29 22:03:28 +02:00
parent c7b2916f37
commit afe786d19a
3 changed files with 37 additions and 8 deletions

View File

@ -155,7 +155,7 @@ module ActiveModelSerializers
# @api private
def parse_attributes(attributes, options)
attributes
transform_keys(attributes, options)
.map { |(k, v)| { field_key(k, options) => v } }
.reduce({}, :merge)
end
@ -182,23 +182,29 @@ module ActiveModelSerializers
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['id'] : nil }
{ "#{prefix_key}_id".to_sym => assoc_data && assoc_data.is_a?(Hash) ? assoc_data[:id] : nil }
end
polymorphic = (options[:polymorphic] || []).include?(assoc_name.to_sym)
hash["#{prefix_key}_type".to_sym] = assoc_data['type'] if polymorphic
hash["#{prefix_key}_type".to_sym] = assoc_data[:type] if polymorphic
hash
end
# @api private
def parse_relationships(relationships, options)
relationships
.map { |(k, v)| parse_relationship(k, v['data'], options) }
transform_keys(relationships, options)
.map { |(k, v)| parse_relationship(k, v[:data], options) }
.reduce({}, :merge)
end
# @api private
def transform_keys(hash, options)
transform = options[:key_transform] || :underscore
KeyTransform.send(transform, hash)
end
end
end
end

View File

@ -32,6 +32,16 @@ module ActiveModelSerializers
hash.deep_transform_keys! { |key| key.to_s.dasherize.to_sym }
end
# Transforms keys to underscore.
# 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 }
end
# Returns the hash unaltered
def unaltered(hash)
hash

View File

@ -20,7 +20,10 @@ module ActionController
'id' => 'zorglub',
'attributes' => {
'title' => 'Ember Hamster',
'src' => 'http://example.com/images/productivity.png'
'src' => 'http://example.com/images/productivity.png',
'image-width' => '200',
'imageHeight' => '200',
'ImageSize' => '1024'
},
'relationships' => {
'author' => {
@ -34,6 +37,12 @@ module ActionController
{ 'type' => 'comments', 'id' => '1' },
{ 'type' => 'comments', 'id' => '2' }
]
},
'related-images' => {
'data' => [
{ 'type' => 'image', 'id' => '7' },
{ 'type' => 'image', 'id' => '8' }
]
}
}
}
@ -46,9 +55,13 @@ module ActionController
'id' => 'zorglub',
'title' => 'Ember Hamster',
'src' => 'http://example.com/images/productivity.png',
'image_width' => '200',
'image_height' => '200',
'image_size' => '1024',
'author_id' => nil,
'photographer_id' => '9',
'comment_ids' => %w(1 2)
'comment_ids' => %w(1 2),
'related_image_ids' => %w(7 8)
}
assert_equal(expected, response)