Skip to content

Commit 4e9e889

Browse files
committed
Singularize and capitalize polymorphic types for presence validation
Singularizing polymorphic association types allows you to use plural or singular type values in your requests as allowed by JSON API. Because ActiveRecord calls #constantize on the polymorphic association type when you use the hash to create a new model if you validate the presence of the related model, you must capitalize the type to avoid a NameError.
1 parent 5af7d96 commit 4e9e889

File tree

7 files changed

+51
-6
lines changed

7 files changed

+51
-6
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ Features:
2626
- [#1340](https://github.com/rails-api/active_model_serializers/pull/1340) Add support for resource-level meta. (@beauby)
2727

2828
Fixes:
29+
- [#1615](https://github.com/rails-api/active_model_serializers/pull/1615) Allow plural polymorphic relationship types when validating
30+
presence. (@dpdawson)
31+
- [#1615](https://github.com/rails-api/active_model_serializers/pull/1615) Capitalize polymorphic association types to prevent error
32+
when ActiveRecord constantizes them when validating presence. (@dpdawson)
2933
- [#1478](https://github.com/rails-api/active_model_serializers/pull/1478) Cache store will now be correctly set when serializers are
3034
loaded *before* Rails initializes. (@bf4)
3135
- [#1570](https://github.com/rails-api/active_model_serializers/pull/1570) Fixed pagination issue with last page size. (@bmorrall)

docs/general/deserialization.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ ActiveModelSerializers::Deserialization
9191
# title: 'Title 1',
9292
# published_at: '2015-12-20',
9393
# author_id: '2',
94-
# author_type: 'user'
94+
# author_type: 'User'
9595
# }
9696
```
9797

lib/active_model_serializers/adapter/json_api/deserialization.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ module Deserialization
6969
# # title: 'Title 1',
7070
# # published_at: '2015-12-20',
7171
# # author_id: '2',
72-
# # author_type: 'people'
72+
# # author_type: 'People'
7373
# # }
7474
#
7575
def parse!(document, options = {})
@@ -188,7 +188,7 @@ def parse_relationship(assoc_name, assoc_data, options)
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'].singularize.capitalize if polymorphic
192192

193193
hash
194194
end

test/active_record_test.rb

+33
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,38 @@ class ActiveRecordTest < ActiveSupport::TestCase
55

66
def setup
77
@resource = ARModels::Post.new
8+
@image = Image.create
9+
end
10+
11+
def test_active_model_record_with_validated_polymorphic_relationship_creation
12+
picture = Picture.create!(picture_params)
13+
14+
assert_equal(@image, picture.imageable)
15+
end
16+
17+
private
18+
19+
def picture_params
20+
params = ActionController::Parameters.new({
21+
data: {
22+
attributes: {
23+
title: 'Picture Title'
24+
},
25+
relationships: {
26+
imageable: {
27+
data: {
28+
type: 'images',
29+
id: @image.id
30+
}
31+
},
32+
},
33+
type: 'pictures'
34+
}
35+
})
36+
37+
ActiveModelSerializers::Deserialization.jsonapi_parse!(
38+
params.to_unsafe_h,
39+
polymorphic: [:imageable]
40+
)
841
end
942
end

test/adapter/json_api/parse_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def test_polymorphic
125125
src: 'http://example.com/images/productivity.png',
126126
author_id: nil,
127127
photographer_id: '9',
128-
photographer_type: 'people',
128+
photographer_type: 'Person',
129129
comment_ids: %w(1 2)
130130
}
131131
assert_equal(expected, parsed_hash)

test/fixtures/active_record.rb

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
end
2727
create_table :pictures, force: true do |t|
2828
t.string :title
29-
t.string :imageable_type
30-
t.string :imageable_id
29+
t.references :imageable, polymorphic: true
30+
t.timestamp null: false
31+
end
32+
create_table :images, force: true do |t|
3133
t.timestamp null: false
3234
end
3335
end

test/fixtures/poro.rb

+6
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ class Employee < ActiveRecord::Base
7878

7979
class Picture < ActiveRecord::Base
8080
belongs_to :imageable, polymorphic: true
81+
82+
validates :imageable, presence: true
83+
end
84+
85+
class Image < ActiveRecord::Base
86+
has_many :pictures, as: :imageable
8187
end
8288

8389
module Spam; end

0 commit comments

Comments
 (0)