Skip to content

Commit afe786d

Browse files
committed
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.
1 parent c7b2916 commit afe786d

File tree

3 files changed

+37
-8
lines changed

3 files changed

+37
-8
lines changed

lib/active_model_serializers/adapter/json_api/deserialization.rb

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def field_key(field, options)
155155

156156
# @api private
157157
def parse_attributes(attributes, options)
158-
attributes
158+
transform_keys(attributes, options)
159159
.map { |(k, v)| { field_key(k, options) => v } }
160160
.reduce({}, :merge)
161161
end
@@ -182,23 +182,29 @@ def parse_relationship(assoc_name, assoc_data, options)
182182
prefix_key = field_key(assoc_name, options).to_s.singularize
183183
hash =
184184
if assoc_data.is_a?(Array)
185-
{ "#{prefix_key}_ids".to_sym => assoc_data.map { |ri| ri['id'] } }
185+
{ "#{prefix_key}_ids".to_sym => assoc_data.map { |ri| ri[:id] } }
186186
else
187-
{ "#{prefix_key}_id".to_sym => assoc_data ? assoc_data['id'] : nil }
187+
{ "#{prefix_key}_id".to_sym => assoc_data && assoc_data.is_a?(Hash) ? assoc_data[:id] : nil }
188188
end
189189

190190
polymorphic = (options[:polymorphic] || []).include?(assoc_name.to_sym)
191-
hash["#{prefix_key}_type".to_sym] = assoc_data['type'] if polymorphic
191+
hash["#{prefix_key}_type".to_sym] = assoc_data[:type] if polymorphic
192192

193193
hash
194194
end
195195

196196
# @api private
197197
def parse_relationships(relationships, options)
198-
relationships
199-
.map { |(k, v)| parse_relationship(k, v['data'], options) }
198+
transform_keys(relationships, options)
199+
.map { |(k, v)| parse_relationship(k, v[:data], options) }
200200
.reduce({}, :merge)
201201
end
202+
203+
# @api private
204+
def transform_keys(hash, options)
205+
transform = options[:key_transform] || :underscore
206+
KeyTransform.send(transform, hash)
207+
end
202208
end
203209
end
204210
end

lib/active_model_serializers/key_transform.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ def dashed(hash)
3232
hash.deep_transform_keys! { |key| key.to_s.dasherize.to_sym }
3333
end
3434

35+
# Transforms keys to underscore.
36+
# This is the default case for deserialization in the JsonApi adapter.
37+
#
38+
# @example:
39+
# "some-key" => "some_key",
40+
# @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L89-L98 ActiveSupport::Inflector.underscore}
41+
def underscore(hash)
42+
hash.deep_transform_keys! { |key| key.to_s.underscore.to_sym }
43+
end
44+
3545
# Returns the hash unaltered
3646
def unaltered(hash)
3747
hash

test/action_controller/json_api/deserialization_test.rb

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ def test_deserialization
2020
'id' => 'zorglub',
2121
'attributes' => {
2222
'title' => 'Ember Hamster',
23-
'src' => 'http://example.com/images/productivity.png'
23+
'src' => 'http://example.com/images/productivity.png',
24+
'image-width' => '200',
25+
'imageHeight' => '200',
26+
'ImageSize' => '1024'
2427
},
2528
'relationships' => {
2629
'author' => {
@@ -34,6 +37,12 @@ def test_deserialization
3437
{ 'type' => 'comments', 'id' => '1' },
3538
{ 'type' => 'comments', 'id' => '2' }
3639
]
40+
},
41+
'related-images' => {
42+
'data' => [
43+
{ 'type' => 'image', 'id' => '7' },
44+
{ 'type' => 'image', 'id' => '8' }
45+
]
3746
}
3847
}
3948
}
@@ -46,9 +55,13 @@ def test_deserialization
4655
'id' => 'zorglub',
4756
'title' => 'Ember Hamster',
4857
'src' => 'http://example.com/images/productivity.png',
58+
'image_width' => '200',
59+
'image_height' => '200',
60+
'image_size' => '1024',
4961
'author_id' => nil,
5062
'photographer_id' => '9',
51-
'comment_ids' => %w(1 2)
63+
'comment_ids' => %w(1 2),
64+
'related_image_ids' => %w(7 8)
5265
}
5366

5467
assert_equal(expected, response)

0 commit comments

Comments
 (0)