Skip to content

Commit 6de3f31

Browse files
NullVoxPopulibf4
authored andcommitted
Namespace separator setting for json-api and tests (#1874)
Adds jsonapi_namespace_separator configuration Also: * Enable getting type from record class without serializer Needs Followup: - #1874 (comment) - #1874 (comment)
1 parent 9217bc2 commit 6de3f31

File tree

7 files changed

+88
-10
lines changed

7 files changed

+88
-10
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Breaking changes:
66

77
Features:
88

9+
- [#1791](https://github.com/rails-api/active_model_serializers/pull/1791) (@bf4, @youroff, @NullVoxPopuli)
10+
- Added `jsonapi_namespace_separator` config option.
11+
912
Fixes:
1013

1114
- [#1833](https://github.com/rails-api/active_model_serializers/pull/1833) Remove relationship links if they are null (@groyoh)

docs/general/configuration_options.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,19 @@ Possible values:
7272
- `:singular`
7373
- `:plural` (default)
7474

75+
##### jsonapi_namespace_separator
76+
77+
Sets separator string for namespaced models to render `type` attribute.
78+
79+
80+
| Separator | Example: Admin::User |
81+
|----|----|
82+
| `'-'` (default) | 'admin-users'
83+
| `'--'` (recommended) | 'admin--users'
84+
85+
See [Recommendation for dasherizing (kebab-case-ing) namespaced object, such as `Admin::User`](https://github.com/json-api/json-api/issues/850)
86+
for more discussion.
87+
7588
##### jsonapi_include_toplevel_object
7689

7790
Include a [top level jsonapi member](http://jsonapi.org/format/#document-jsonapi-object)

lib/active_model/serializer/configuration.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ def config.array_serializer
2121

2222
config.default_includes = '*'
2323
config.adapter = :attributes
24+
config.key_transform = nil
2425
config.jsonapi_resource_type = :plural
26+
config.jsonapi_namespace_separator = '-'.freeze
2527
config.jsonapi_version = '1.0'
2628
config.jsonapi_toplevel_meta = {}
2729
# Make JSON API top-level jsonapi member opt-in
2830
# ref: http://jsonapi.org/format/#document-top-level
2931
config.jsonapi_include_toplevel_object = false
30-
config.key_transform = nil
3132

3233
config.schema_path = 'test/support/schemas'
3334
end

lib/active_model_serializers/adapter/json_api/resource_identifier.rb

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,30 @@ module ActiveModelSerializers
22
module Adapter
33
class JsonApi
44
class ResourceIdentifier
5+
def self.type_for(class_name, serializer_type = nil, transform_options = {})
6+
if serializer_type
7+
raw_type = serializer_type
8+
else
9+
inflection =
10+
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
11+
:singularize
12+
else
13+
:pluralize
14+
end
15+
16+
raw_type = class_name.underscore
17+
raw_type = ActiveSupport::Inflector.public_send(inflection, raw_type)
18+
raw_type
19+
.gsub!('/'.freeze, ActiveModelSerializers.config.jsonapi_namespace_separator)
20+
raw_type
21+
end
22+
JsonApi.send(:transform_key_casing!, raw_type, transform_options)
23+
end
24+
525
# {http://jsonapi.org/format/#document-resource-identifier-objects Resource Identifier Objects}
626
def initialize(serializer, options)
727
@id = id_for(serializer)
8-
@type = JsonApi.send(:transform_key_casing!, type_for(serializer),
9-
options)
28+
@type = type_for(serializer, options)
1029
end
1130

1231
def as_json
@@ -19,13 +38,8 @@ def as_json
1938

2039
private
2140

22-
def type_for(serializer)
23-
return serializer._type if serializer._type
24-
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
25-
serializer.object.class.model_name.singular
26-
else
27-
serializer.object.class.model_name.plural
28-
end
41+
def type_for(serializer, transform_options)
42+
self.class.type_for(serializer.object.class.name, serializer._type, transform_options)
2943
end
3044

3145
def id_for(serializer)

test/adapter/json_api/linked_test.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,25 @@ def test_underscore_model_namespace_for_linked_resource_type
223223
assert_equal expected, relationships
224224
end
225225

226+
def test_underscore_model_namespace_with_namespace_separator_for_linked_resource_type
227+
spammy_post = Post.new(id: 123)
228+
spammy_post.related = [Spam::UnrelatedLink.new(id: 456)]
229+
serializer = SpammyPostSerializer.new(spammy_post)
230+
adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
231+
relationships = with_namespace_separator '--' do
232+
adapter.serializable_hash[:data][:relationships]
233+
end
234+
expected = {
235+
related: {
236+
data: [{
237+
type: 'spam--unrelated-links',
238+
id: '456'
239+
}]
240+
}
241+
}
242+
assert_equal expected, relationships
243+
end
244+
226245
def test_multiple_references_to_same_resource
227246
serializer = ActiveModel::Serializer::CollectionSerializer.new([@first_comment, @second_comment])
228247
adapter = ActiveModelSerializers::Adapter::JsonApi.new(

test/adapter/json_api/resource_identifier_test.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,26 @@ def test_plural_type
3939
test_type_inflection(AuthorSerializer, 'authors', :plural)
4040
end
4141

42+
def test_type_with_namespace
43+
Object.const_set(:Admin, Module.new)
44+
model = Class.new(::Model)
45+
Admin.const_set(:PowerUser, model)
46+
serializer = Class.new(ActiveModel::Serializer)
47+
Admin.const_set(:PowerUserSerializer, serializer)
48+
with_namespace_separator '--' do
49+
admin_user = Admin::PowerUser.new
50+
serializer = Admin::PowerUserSerializer.new(admin_user)
51+
expected = {
52+
id: admin_user.id,
53+
type: 'admin--power-users'
54+
}
55+
56+
identifier = ResourceIdentifier.new(serializer, {})
57+
actual = identifier.as_json
58+
assert_equal(expected, actual)
59+
end
60+
end
61+
4262
def test_id_defined_on_object
4363
test_id(AuthorSerializer, @model.id.to_s)
4464
end

test/support/serialization_testing.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ def generate_cached_serializer(obj)
99
ActiveModelSerializers::SerializableResource.new(obj).to_json
1010
end
1111

12+
def with_namespace_separator(seperator)
13+
original_seperator = ActiveModelSerializers.config.jsonapi_namespace_separator
14+
ActiveModelSerializers.config.jsonapi_namespace_separator = seperator
15+
yield
16+
ensure
17+
ActiveModelSerializers.config.jsonapi_namespace_separator = original_seperator
18+
end
19+
1220
# Aliased as :with_configured_adapter to clarify that
1321
# this method tests the configured adapter.
1422
# When not testing configuration, it may be preferable

0 commit comments

Comments
 (0)