Skip to content

Commit 8555c92

Browse files
committed
namespace separator setting for json-api and tests
documentation Type transform setting and transformer, name fixed in tests
1 parent d30aa4c commit 8555c92

File tree

6 files changed

+74
-36
lines changed

6 files changed

+74
-36
lines changed

docs/general/configuration_options.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,21 @@ Possible values:
6363
- `:singular`
6464
- `:plural` (default)
6565

66+
##### jsonapi_namespace_separator
67+
68+
Sets separator string for namespaced models to render `type` attribute. Default value is `--`.
69+
70+
##### jsonapi_type_transform
71+
72+
Provides transform for `type` attribute. Class name `NicePost` gets converted into `nice_post`, `nice-post`, `NicePost` or `nicePost` depending on selected setting.
73+
74+
Possible values:
75+
76+
- `:underscore` (default)
77+
- `:dashed`
78+
- `:camel`
79+
- `:snake`
80+
6681
##### jsonapi_include_toplevel_object
6782

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

lib/active_model/serializer/configuration.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ def config.array_serializer
2121

2222
config.adapter = :attributes
2323
config.jsonapi_resource_type = :plural
24+
config.jsonapi_namespace_separator = '--'.freeze
25+
config.jsonapi_type_transform = :underscore
2426
config.jsonapi_version = '1.0'
2527
config.jsonapi_toplevel_meta = {}
2628
# Make JSON API top-level jsonapi member opt-in

lib/active_model_serializers/adapter/json_api/resource_identifier.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ def as_json
2020

2121
def type_for(serializer)
2222
return serializer._type if serializer._type
23-
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
24-
serializer.object.class.model_name.singular
25-
else
26-
serializer.object.class.model_name.plural
23+
type = serializer.object.class.to_s.split('::')
24+
type.map! { |t| KeyTransform.transform(t, ActiveModelSerializers.config.jsonapi_type_transform) }
25+
type = type.join ActiveModelSerializers.config.jsonapi_namespace_separator
26+
if ActiveModelSerializers.config.jsonapi_resource_type == :plural
27+
type = type.pluralize
2728
end
29+
type
2830
end
2931

3032
def id_for(serializer)

lib/active_model_serializers/key_transform.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,26 @@ def underscore(hash)
4646
def unaltered(hash)
4747
hash
4848
end
49+
50+
# Transforms string to selected case
51+
# Accepts string in any case: 'camel', 'undescore', 'dashed'.
52+
#
53+
# @example:
54+
# transform('SomeClass', :underscore) => 'some_class'
55+
# transform('some_class', :snake) => 'someClass'
56+
# etc...
57+
def transform(string, type)
58+
string = string.underscore
59+
case type.to_sym
60+
when :dashed
61+
string.dasherize
62+
when :camel
63+
string.camelize
64+
when :snake
65+
string.camelize(:lower)
66+
else
67+
string
68+
end
69+
end
4970
end
5071
end

test/adapter/json_api/linked_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def test_underscore_model_namespace_for_linked_resource_type
216216
expected = {
217217
related: {
218218
data: [{
219-
type: 'spam_unrelated_links',
219+
type: 'spam--unrelated_links',
220220
id: '456'
221221
}]
222222
}

test/adapter/json_api/resource_identifier_test.rb

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,62 +22,60 @@ class FragmentedSerializer < ActiveModel::Serializer; end
2222
end
2323

2424
def test_defined_type
25-
test_type(WithDefinedTypeSerializer, 'with_defined_type')
25+
assert_identifier(WithDefinedTypeSerializer.new(@model), type: 'with_defined_type')
2626
end
2727

2828
def test_singular_type
29-
test_type_inflection(AuthorSerializer, 'author', :singular)
29+
assert_with_confing(AuthorSerializer.new(@model), type: 'author', inflection: :singular)
3030
end
3131

3232
def test_plural_type
33-
test_type_inflection(AuthorSerializer, 'authors', :plural)
33+
assert_with_confing(AuthorSerializer.new(@model), type: 'authors', inflection: :plural)
34+
end
35+
36+
def test_type_with_namespace
37+
spam = Spam::UnrelatedLink.new
38+
assert_identifier(Spam::UnrelatedLinkSerializer.new(spam), type: 'spam--unrelated_links')
39+
end
40+
41+
def test_type_with_custom_namespace
42+
spam = Spam::UnrelatedLink.new
43+
assert_with_confing(Spam::UnrelatedLinkSerializer.new(spam), type: 'spam/unrelated_links', namespace_separator: '/')
3444
end
3545

3646
def test_id_defined_on_object
37-
test_id(AuthorSerializer, @model.id.to_s)
47+
assert_identifier(AuthorSerializer.new(@model), id: @model.id.to_s)
3848
end
3949

4050
def test_id_defined_on_serializer
41-
test_id(WithDefinedIdSerializer, 'special_id')
51+
assert_identifier(WithDefinedIdSerializer.new(@model), id: 'special_id')
4252
end
4353

4454
def test_id_defined_on_fragmented
4555
FragmentedSerializer.fragmented(WithDefinedIdSerializer.new(@model))
46-
test_id(FragmentedSerializer, 'special_id')
56+
assert_identifier(FragmentedSerializer.new(@model), id: 'special_id')
4757
end
4858

4959
private
5060

51-
def test_type_inflection(serializer_class, expected_type, inflection)
52-
original_inflection = ActiveModelSerializers.config.jsonapi_resource_type
53-
ActiveModelSerializers.config.jsonapi_resource_type = inflection
54-
test_type(serializer_class, expected_type)
61+
def assert_with_confing(serializer, opts = {})
62+
inflection = ActiveModelSerializers.config.jsonapi_resource_type
63+
namespace_separator = ActiveModelSerializers.config.jsonapi_namespace_separator
64+
ActiveModelSerializers.config.jsonapi_resource_type = opts.fetch(:inflection, inflection)
65+
ActiveModelSerializers.config.jsonapi_namespace_separator = opts.fetch(:namespace_separator, namespace_separator)
66+
assert_identifier(serializer, opts)
5567
ensure
56-
ActiveModelSerializers.config.jsonapi_resource_type = original_inflection
57-
end
58-
59-
def test_type(serializer_class, expected_type)
60-
serializer = serializer_class.new(@model)
61-
resource_identifier = ResourceIdentifier.new(serializer)
62-
expected = {
63-
id: @model.id.to_s,
64-
type: expected_type
65-
}
66-
67-
assert_equal(expected, resource_identifier.as_json)
68+
ActiveModelSerializers.config.jsonapi_resource_type = inflection
69+
ActiveModelSerializers.config.jsonapi_namespace_separator = namespace_separator
6870
end
6971

70-
def test_id(serializer_class, id)
71-
serializer = serializer_class.new(@model)
72-
resource_identifier = ResourceIdentifier.new(serializer)
73-
inflection = ActiveModelSerializers.config.jsonapi_resource_type
74-
type = @model.class.model_name.send(inflection)
72+
def assert_identifier(serializer, opts = {})
73+
identifier = ResourceIdentifier.new(serializer)
7574
expected = {
76-
id: id,
77-
type: type
75+
id: opts.fetch(:id, identifier.as_json[:id]),
76+
type: opts.fetch(:type, identifier.as_json[:type])
7877
}
79-
80-
assert_equal(expected, resource_identifier.as_json)
78+
assert_equal(expected, identifier.as_json)
8179
end
8280
end
8381
end

0 commit comments

Comments
 (0)