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:

- https://github.com/rails-api/active_model_serializers/pull/1874#discussion_r74607042 
- https://github.com/rails-api/active_model_serializers/pull/1874#discussion_r74607734
This commit is contained in:
L. Preston Sego III 2016-08-12 13:54:42 -04:00 committed by Benjamin Fleischer
parent 9217bc2ec4
commit 6de3f31b6e
7 changed files with 88 additions and 10 deletions

View File

@ -6,6 +6,9 @@ Breaking changes:
Features: Features:
- [#1791](https://github.com/rails-api/active_model_serializers/pull/1791) (@bf4, @youroff, @NullVoxPopuli)
- Added `jsonapi_namespace_separator` config option.
Fixes: Fixes:
- [#1833](https://github.com/rails-api/active_model_serializers/pull/1833) Remove relationship links if they are null (@groyoh) - [#1833](https://github.com/rails-api/active_model_serializers/pull/1833) Remove relationship links if they are null (@groyoh)

View File

@ -72,6 +72,19 @@ Possible values:
- `:singular` - `:singular`
- `:plural` (default) - `:plural` (default)
##### jsonapi_namespace_separator
Sets separator string for namespaced models to render `type` attribute.
| Separator | Example: Admin::User |
|----|----|
| `'-'` (default) | 'admin-users'
| `'--'` (recommended) | 'admin--users'
See [Recommendation for dasherizing (kebab-case-ing) namespaced object, such as `Admin::User`](https://github.com/json-api/json-api/issues/850)
for more discussion.
##### jsonapi_include_toplevel_object ##### jsonapi_include_toplevel_object
Include a [top level jsonapi member](http://jsonapi.org/format/#document-jsonapi-object) Include a [top level jsonapi member](http://jsonapi.org/format/#document-jsonapi-object)

View File

@ -21,13 +21,14 @@ module ActiveModel
config.default_includes = '*' config.default_includes = '*'
config.adapter = :attributes config.adapter = :attributes
config.key_transform = nil
config.jsonapi_resource_type = :plural config.jsonapi_resource_type = :plural
config.jsonapi_namespace_separator = '-'.freeze
config.jsonapi_version = '1.0' config.jsonapi_version = '1.0'
config.jsonapi_toplevel_meta = {} config.jsonapi_toplevel_meta = {}
# Make JSON API top-level jsonapi member opt-in # Make JSON API top-level jsonapi member opt-in
# ref: http://jsonapi.org/format/#document-top-level # ref: http://jsonapi.org/format/#document-top-level
config.jsonapi_include_toplevel_object = false config.jsonapi_include_toplevel_object = false
config.key_transform = nil
config.schema_path = 'test/support/schemas' config.schema_path = 'test/support/schemas'
end end

View File

@ -2,11 +2,30 @@ module ActiveModelSerializers
module Adapter module Adapter
class JsonApi class JsonApi
class ResourceIdentifier class ResourceIdentifier
def self.type_for(class_name, serializer_type = nil, transform_options = {})
if serializer_type
raw_type = serializer_type
else
inflection =
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
:singularize
else
:pluralize
end
raw_type = class_name.underscore
raw_type = ActiveSupport::Inflector.public_send(inflection, raw_type)
raw_type
.gsub!('/'.freeze, ActiveModelSerializers.config.jsonapi_namespace_separator)
raw_type
end
JsonApi.send(:transform_key_casing!, raw_type, transform_options)
end
# {http://jsonapi.org/format/#document-resource-identifier-objects Resource Identifier Objects} # {http://jsonapi.org/format/#document-resource-identifier-objects Resource Identifier Objects}
def initialize(serializer, options) def initialize(serializer, options)
@id = id_for(serializer) @id = id_for(serializer)
@type = JsonApi.send(:transform_key_casing!, type_for(serializer), @type = type_for(serializer, options)
options)
end end
def as_json def as_json
@ -19,13 +38,8 @@ module ActiveModelSerializers
private private
def type_for(serializer) def type_for(serializer, transform_options)
return serializer._type if serializer._type self.class.type_for(serializer.object.class.name, serializer._type, transform_options)
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
serializer.object.class.model_name.singular
else
serializer.object.class.model_name.plural
end
end end
def id_for(serializer) def id_for(serializer)

View File

@ -223,6 +223,25 @@ module ActiveModelSerializers
assert_equal expected, relationships assert_equal expected, relationships
end end
def test_underscore_model_namespace_with_namespace_separator_for_linked_resource_type
spammy_post = Post.new(id: 123)
spammy_post.related = [Spam::UnrelatedLink.new(id: 456)]
serializer = SpammyPostSerializer.new(spammy_post)
adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
relationships = with_namespace_separator '--' do
adapter.serializable_hash[:data][:relationships]
end
expected = {
related: {
data: [{
type: 'spam--unrelated-links',
id: '456'
}]
}
}
assert_equal expected, relationships
end
def test_multiple_references_to_same_resource def test_multiple_references_to_same_resource
serializer = ActiveModel::Serializer::CollectionSerializer.new([@first_comment, @second_comment]) serializer = ActiveModel::Serializer::CollectionSerializer.new([@first_comment, @second_comment])
adapter = ActiveModelSerializers::Adapter::JsonApi.new( adapter = ActiveModelSerializers::Adapter::JsonApi.new(

View File

@ -39,6 +39,26 @@ module ActiveModelSerializers
test_type_inflection(AuthorSerializer, 'authors', :plural) test_type_inflection(AuthorSerializer, 'authors', :plural)
end end
def test_type_with_namespace
Object.const_set(:Admin, Module.new)
model = Class.new(::Model)
Admin.const_set(:PowerUser, model)
serializer = Class.new(ActiveModel::Serializer)
Admin.const_set(:PowerUserSerializer, serializer)
with_namespace_separator '--' do
admin_user = Admin::PowerUser.new
serializer = Admin::PowerUserSerializer.new(admin_user)
expected = {
id: admin_user.id,
type: 'admin--power-users'
}
identifier = ResourceIdentifier.new(serializer, {})
actual = identifier.as_json
assert_equal(expected, actual)
end
end
def test_id_defined_on_object def test_id_defined_on_object
test_id(AuthorSerializer, @model.id.to_s) test_id(AuthorSerializer, @model.id.to_s)
end end

View File

@ -9,6 +9,14 @@ module SerializationTesting
ActiveModelSerializers::SerializableResource.new(obj).to_json ActiveModelSerializers::SerializableResource.new(obj).to_json
end end
def with_namespace_separator(seperator)
original_seperator = ActiveModelSerializers.config.jsonapi_namespace_separator
ActiveModelSerializers.config.jsonapi_namespace_separator = seperator
yield
ensure
ActiveModelSerializers.config.jsonapi_namespace_separator = original_seperator
end
# Aliased as :with_configured_adapter to clarify that # Aliased as :with_configured_adapter to clarify that
# this method tests the configured adapter. # this method tests the configured adapter.
# When not testing configuration, it may be preferable # When not testing configuration, it may be preferable