active_model_serializers 0.10.0 → 0.10.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -5
- data/.travis.yml +17 -5
- data/CHANGELOG.md +126 -2
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +5 -2
- data/README.md +166 -26
- data/Rakefile +3 -32
- data/active_model_serializers.gemspec +22 -25
- data/appveyor.yml +9 -3
- data/bin/rubocop +38 -0
- data/docs/README.md +2 -1
- data/docs/general/adapters.md +29 -11
- data/docs/general/caching.md +7 -1
- data/docs/general/configuration_options.md +70 -1
- data/docs/general/deserialization.md +1 -1
- data/docs/general/fields.md +31 -0
- data/docs/general/getting_started.md +1 -1
- data/docs/general/logging.md +7 -0
- data/docs/general/rendering.md +62 -24
- data/docs/general/serializers.md +121 -13
- data/docs/howto/add_pagination_links.md +16 -17
- data/docs/howto/add_relationship_links.md +140 -0
- data/docs/howto/add_root_key.md +4 -0
- data/docs/howto/grape_integration.md +42 -0
- data/docs/howto/outside_controller_use.md +12 -4
- data/docs/howto/passing_arbitrary_options.md +2 -2
- data/docs/howto/serialize_poro.md +46 -5
- data/docs/howto/test.md +2 -0
- data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
- data/docs/integrations/ember-and-json-api.md +67 -32
- data/docs/jsonapi/schema.md +1 -1
- data/lib/action_controller/serialization.rb +13 -3
- data/lib/active_model/serializer/adapter/base.rb +2 -0
- data/lib/active_model/serializer/array_serializer.rb +8 -5
- data/lib/active_model/serializer/association.rb +62 -10
- data/lib/active_model/serializer/belongs_to_reflection.rb +4 -3
- data/lib/active_model/serializer/collection_serializer.rb +35 -12
- data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +82 -115
- data/lib/active_model/serializer/error_serializer.rb +11 -7
- data/lib/active_model/serializer/errors_serializer.rb +25 -20
- data/lib/active_model/serializer/has_many_reflection.rb +3 -3
- data/lib/active_model/serializer/has_one_reflection.rb +1 -4
- data/lib/active_model/serializer/lazy_association.rb +95 -0
- data/lib/active_model/serializer/lint.rb +134 -130
- data/lib/active_model/serializer/reflection.rb +127 -67
- data/lib/active_model/serializer/version.rb +1 -1
- data/lib/active_model/serializer.rb +296 -79
- data/lib/active_model_serializers/adapter/attributes.rb +3 -66
- data/lib/active_model_serializers/adapter/base.rb +39 -39
- data/lib/active_model_serializers/adapter/json_api/deserialization.rb +1 -1
- data/lib/active_model_serializers/adapter/json_api/link.rb +1 -1
- data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +8 -1
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +63 -23
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +32 -9
- data/lib/active_model_serializers/adapter/json_api.rb +71 -57
- data/lib/active_model_serializers/adapter.rb +6 -0
- data/lib/active_model_serializers/deprecate.rb +1 -2
- data/lib/active_model_serializers/deserialization.rb +2 -0
- data/lib/active_model_serializers/lookup_chain.rb +80 -0
- data/lib/active_model_serializers/model.rb +109 -28
- data/lib/active_model_serializers/railtie.rb +3 -1
- data/lib/active_model_serializers/register_jsonapi_renderer.rb +44 -31
- data/lib/active_model_serializers/serializable_resource.rb +6 -5
- data/lib/active_model_serializers/serialization_context.rb +10 -3
- data/lib/active_model_serializers/test/schema.rb +2 -2
- data/lib/active_model_serializers.rb +15 -0
- data/lib/generators/rails/resource_override.rb +1 -1
- data/lib/generators/rails/serializer_generator.rb +4 -4
- data/lib/grape/active_model_serializers.rb +7 -5
- data/lib/grape/formatters/active_model_serializers.rb +19 -2
- data/lib/grape/helpers/active_model_serializers.rb +1 -0
- data/lib/tasks/rubocop.rake +53 -0
- data/test/action_controller/adapter_selector_test.rb +14 -5
- data/test/action_controller/explicit_serializer_test.rb +5 -4
- data/test/action_controller/json/include_test.rb +106 -27
- data/test/action_controller/json_api/errors_test.rb +8 -9
- data/test/action_controller/json_api/fields_test.rb +66 -0
- data/test/action_controller/json_api/linked_test.rb +29 -24
- data/test/action_controller/json_api/pagination_test.rb +19 -19
- data/test/action_controller/json_api/transform_test.rb +11 -3
- data/test/action_controller/lookup_proc_test.rb +49 -0
- data/test/action_controller/namespace_lookup_test.rb +232 -0
- data/test/action_controller/serialization_scope_name_test.rb +12 -6
- data/test/action_controller/serialization_test.rb +12 -9
- data/test/active_model_serializers/json_pointer_test.rb +15 -13
- data/test/active_model_serializers/model_test.rb +137 -4
- data/test/active_model_serializers/railtie_test_isolated.rb +12 -7
- data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +161 -0
- data/test/active_model_serializers/serialization_context_test_isolated.rb +23 -10
- data/test/active_model_serializers/test/schema_test.rb +3 -2
- data/test/adapter/attributes_test.rb +40 -0
- data/test/adapter/json/collection_test.rb +14 -0
- data/test/adapter/json/has_many_test.rb +10 -2
- data/test/adapter/json/transform_test.rb +15 -15
- data/test/adapter/json_api/collection_test.rb +4 -3
- data/test/adapter/json_api/errors_test.rb +17 -19
- data/test/adapter/json_api/fields_test.rb +12 -3
- data/test/adapter/json_api/has_many_test.rb +49 -20
- data/test/adapter/json_api/include_data_if_sideloaded_test.rb +183 -0
- data/test/adapter/json_api/json_api_test.rb +5 -7
- data/test/adapter/json_api/linked_test.rb +33 -12
- data/test/adapter/json_api/links_test.rb +4 -2
- data/test/adapter/json_api/pagination_links_test.rb +35 -8
- data/test/adapter/json_api/relationship_test.rb +309 -73
- data/test/adapter/json_api/resource_identifier_test.rb +27 -2
- data/test/adapter/json_api/resource_meta_test.rb +3 -3
- data/test/adapter/json_api/transform_test.rb +263 -253
- data/test/adapter/json_api/type_test.rb +1 -1
- data/test/adapter/json_test.rb +8 -7
- data/test/adapter/null_test.rb +1 -2
- data/test/adapter/polymorphic_test.rb +5 -5
- data/test/adapter_test.rb +1 -1
- data/test/benchmark/app.rb +1 -1
- data/test/benchmark/benchmarking_support.rb +1 -1
- data/test/benchmark/bm_active_record.rb +81 -0
- data/test/benchmark/bm_adapter.rb +38 -0
- data/test/benchmark/bm_caching.rb +16 -16
- data/test/benchmark/bm_lookup_chain.rb +83 -0
- data/test/benchmark/bm_transform.rb +21 -10
- data/test/benchmark/controllers.rb +16 -17
- data/test/benchmark/fixtures.rb +72 -72
- data/test/cache_test.rb +235 -69
- data/test/collection_serializer_test.rb +25 -12
- data/test/fixtures/active_record.rb +45 -10
- data/test/fixtures/poro.rb +124 -181
- data/test/generators/serializer_generator_test.rb +23 -5
- data/test/grape_test.rb +170 -56
- data/test/lint_test.rb +1 -1
- data/test/logger_test.rb +13 -11
- data/test/serializable_resource_test.rb +18 -22
- data/test/serializers/association_macros_test.rb +3 -2
- data/test/serializers/associations_test.rb +178 -49
- data/test/serializers/attribute_test.rb +5 -3
- data/test/serializers/attributes_test.rb +1 -1
- data/test/serializers/caching_configuration_test_isolated.rb +6 -6
- data/test/serializers/fieldset_test.rb +1 -1
- data/test/serializers/meta_test.rb +12 -6
- data/test/serializers/options_test.rb +17 -6
- data/test/serializers/read_attribute_for_serialization_test.rb +3 -3
- data/test/serializers/reflection_test.rb +427 -0
- data/test/serializers/root_test.rb +1 -1
- data/test/serializers/serialization_test.rb +2 -2
- data/test/serializers/serializer_for_test.rb +12 -10
- data/test/serializers/serializer_for_with_namespace_test.rb +88 -0
- data/test/support/isolated_unit.rb +5 -2
- data/test/support/rails5_shims.rb +8 -2
- data/test/support/rails_app.rb +2 -9
- data/test/support/serialization_testing.rb +23 -5
- data/test/test_helper.rb +13 -0
- metadata +105 -42
- data/.rubocop_todo.yml +0 -167
- data/docs/ARCHITECTURE.md +0 -126
- data/lib/active_model/serializer/associations.rb +0 -100
- data/lib/active_model/serializer/attributes.rb +0 -82
- data/lib/active_model/serializer/collection_reflection.rb +0 -7
- data/lib/active_model/serializer/configuration.rb +0 -35
- data/lib/active_model/serializer/include_tree.rb +0 -111
- data/lib/active_model/serializer/links.rb +0 -35
- data/lib/active_model/serializer/meta.rb +0 -29
- data/lib/active_model/serializer/singular_reflection.rb +0 -7
- data/lib/active_model/serializer/type.rb +0 -25
- data/lib/active_model_serializers/key_transform.rb +0 -70
- data/test/active_model_serializers/key_transform_test.rb +0 -263
- data/test/adapter/json_api/relationships_test.rb +0 -199
- data/test/include_tree/from_include_args_test.rb +0 -26
- data/test/include_tree/from_string_test.rb +0 -94
- data/test/include_tree/include_args_to_hash_test.rb +0 -64
@@ -5,47 +5,87 @@ module ActiveModelSerializers
|
|
5
5
|
# {http://jsonapi.org/format/#document-resource-object-related-resource-links Document Resource Object Related Resource Links}
|
6
6
|
# {http://jsonapi.org/format/#document-links Document Links}
|
7
7
|
# {http://jsonapi.org/format/#document-resource-object-linkage Document Resource Relationship Linkage}
|
8
|
-
# {http://jsonapi.org/format/#document-meta
|
9
|
-
def initialize(parent_serializer,
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@association_options = args.fetch(:options, {})
|
8
|
+
# {http://jsonapi.org/format/#document-meta Document Meta}
|
9
|
+
def initialize(parent_serializer, serializable_resource_options, association)
|
10
|
+
@parent_serializer = parent_serializer
|
11
|
+
@association = association
|
13
12
|
@serializable_resource_options = serializable_resource_options
|
14
|
-
@data = data_for(serializer)
|
15
|
-
@links = args.fetch(:links, {}).each_with_object({}) do |(key, value), hash|
|
16
|
-
hash[key] = ActiveModelSerializers::Adapter::JsonApi::Link.new(parent_serializer, value).as_json
|
17
|
-
end
|
18
|
-
meta = args.fetch(:meta, nil)
|
19
|
-
@meta = meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta
|
20
13
|
end
|
21
14
|
|
22
15
|
def as_json
|
23
16
|
hash = {}
|
24
|
-
|
25
|
-
|
17
|
+
|
18
|
+
hash[:data] = data_for(association) if association.include_data?
|
19
|
+
|
20
|
+
links = links_for(association)
|
26
21
|
hash[:links] = links if links.any?
|
27
|
-
|
22
|
+
|
23
|
+
meta = meta_for(association)
|
28
24
|
hash[:meta] = meta if meta
|
25
|
+
hash[:meta] = {} if hash.empty?
|
29
26
|
|
30
27
|
hash
|
31
28
|
end
|
32
29
|
|
33
30
|
protected
|
34
31
|
|
35
|
-
attr_reader :
|
36
|
-
:association_options, :links, :meta
|
32
|
+
attr_reader :parent_serializer, :serializable_resource_options, :association
|
37
33
|
|
38
34
|
private
|
39
35
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
ResourceIdentifier.new(serializer, serializable_resource_options).as_json
|
36
|
+
# TODO(BF): Avoid db hit on belong_to_ releationship by using foreign_key on self
|
37
|
+
def data_for(association)
|
38
|
+
if association.collection?
|
39
|
+
data_for_many(association)
|
40
|
+
else
|
41
|
+
data_for_one(association)
|
47
42
|
end
|
48
43
|
end
|
44
|
+
|
45
|
+
def data_for_one(association)
|
46
|
+
if association.belongs_to? &&
|
47
|
+
parent_serializer.object.respond_to?(association.reflection.foreign_key)
|
48
|
+
id = parent_serializer.object.send(association.reflection.foreign_key)
|
49
|
+
type = association.reflection.type.to_s
|
50
|
+
ResourceIdentifier.for_type_with_id(type, id, serializable_resource_options)
|
51
|
+
else
|
52
|
+
# TODO(BF): Process relationship without evaluating lazy_association
|
53
|
+
serializer = association.lazy_association.serializer
|
54
|
+
if (virtual_value = association.virtual_value)
|
55
|
+
virtual_value
|
56
|
+
elsif serializer && association.object
|
57
|
+
ResourceIdentifier.new(serializer, serializable_resource_options).as_json
|
58
|
+
else
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def data_for_many(association)
|
65
|
+
# TODO(BF): Process relationship without evaluating lazy_association
|
66
|
+
collection_serializer = association.lazy_association.serializer
|
67
|
+
if collection_serializer.respond_to?(:each)
|
68
|
+
collection_serializer.map do |serializer|
|
69
|
+
ResourceIdentifier.new(serializer, serializable_resource_options).as_json
|
70
|
+
end
|
71
|
+
elsif (virtual_value = association.virtual_value)
|
72
|
+
virtual_value
|
73
|
+
else
|
74
|
+
[]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def links_for(association)
|
79
|
+
association.links.each_with_object({}) do |(key, value), hash|
|
80
|
+
result = Link.new(parent_serializer, value).as_json
|
81
|
+
hash[key] = result if result
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def meta_for(association)
|
86
|
+
meta = association.meta
|
87
|
+
meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta
|
88
|
+
end
|
49
89
|
end
|
50
90
|
end
|
51
91
|
end
|
@@ -2,14 +2,42 @@ module ActiveModelSerializers
|
|
2
2
|
module Adapter
|
3
3
|
class JsonApi
|
4
4
|
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
|
+
|
25
|
+
def self.for_type_with_id(type, id, options)
|
26
|
+
return nil if id.blank?
|
27
|
+
{
|
28
|
+
id: id.to_s,
|
29
|
+
type: type_for(:no_class_needed, type, options)
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
5
33
|
# {http://jsonapi.org/format/#document-resource-identifier-objects Resource Identifier Objects}
|
6
34
|
def initialize(serializer, options)
|
7
35
|
@id = id_for(serializer)
|
8
|
-
@type =
|
9
|
-
options)
|
36
|
+
@type = type_for(serializer, options)
|
10
37
|
end
|
11
38
|
|
12
39
|
def as_json
|
40
|
+
return nil if id.blank?
|
13
41
|
{ id: id, type: type }
|
14
42
|
end
|
15
43
|
|
@@ -19,13 +47,8 @@ module ActiveModelSerializers
|
|
19
47
|
|
20
48
|
private
|
21
49
|
|
22
|
-
def type_for(serializer)
|
23
|
-
|
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
|
50
|
+
def type_for(serializer, transform_options)
|
51
|
+
self.class.type_for(serializer.object.class.name, serializer._type, transform_options)
|
29
52
|
end
|
30
53
|
|
31
54
|
def id_for(serializer)
|
@@ -31,16 +31,27 @@ module ActiveModelSerializers
|
|
31
31
|
autoload :Error
|
32
32
|
autoload :Deserialization
|
33
33
|
|
34
|
+
def self.default_key_transform
|
35
|
+
:dash
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.fragment_cache(cached_hash, non_cached_hash, root = true)
|
39
|
+
core_cached = cached_hash.first
|
40
|
+
core_non_cached = non_cached_hash.first
|
41
|
+
no_root_cache = cached_hash.delete_if { |key, _value| key == core_cached[0] }
|
42
|
+
no_root_non_cache = non_cached_hash.delete_if { |key, _value| key == core_non_cached[0] }
|
43
|
+
cached_resource = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1]
|
44
|
+
hash = root ? { root => cached_resource } : cached_resource
|
45
|
+
|
46
|
+
hash.deep_merge no_root_non_cache.deep_merge no_root_cache
|
47
|
+
end
|
48
|
+
|
34
49
|
def initialize(serializer, options = {})
|
35
50
|
super
|
36
|
-
@
|
51
|
+
@include_directive = JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
|
37
52
|
@fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
|
38
53
|
end
|
39
54
|
|
40
|
-
def self.default_key_transform
|
41
|
-
:dash
|
42
|
-
end
|
43
|
-
|
44
55
|
# {http://jsonapi.org/format/#crud Requests are transactional, i.e. success or failure}
|
45
56
|
# {http://jsonapi.org/format/#document-top-level data and errors MUST NOT coexist in the same document.}
|
46
57
|
def serializable_hash(*)
|
@@ -52,6 +63,11 @@ module ActiveModelSerializers
|
|
52
63
|
self.class.transform_key_casing!(document, instance_options)
|
53
64
|
end
|
54
65
|
|
66
|
+
def fragment_cache(cached_hash, non_cached_hash)
|
67
|
+
root = !instance_options.include?(:include)
|
68
|
+
self.class.fragment_cache(cached_hash, non_cached_hash, root)
|
69
|
+
end
|
70
|
+
|
55
71
|
# {http://jsonapi.org/format/#document-top-level Primary data}
|
56
72
|
# definition:
|
57
73
|
# ☐ toplevel_data (required)
|
@@ -174,18 +190,6 @@ module ActiveModelSerializers
|
|
174
190
|
hash
|
175
191
|
end
|
176
192
|
|
177
|
-
def fragment_cache(cached_hash, non_cached_hash)
|
178
|
-
root = false if instance_options.include?(:include)
|
179
|
-
core_cached = cached_hash.first
|
180
|
-
core_non_cached = non_cached_hash.first
|
181
|
-
no_root_cache = cached_hash.delete_if { |key, _value| key == core_cached[0] }
|
182
|
-
no_root_non_cache = non_cached_hash.delete_if { |key, _value| key == core_non_cached[0] }
|
183
|
-
cached_resource = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1]
|
184
|
-
hash = root ? { root => cached_resource } : cached_resource
|
185
|
-
|
186
|
-
hash.deep_merge no_root_non_cache.deep_merge no_root_cache
|
187
|
-
end
|
188
|
-
|
189
193
|
protected
|
190
194
|
|
191
195
|
attr_reader :fieldset
|
@@ -231,17 +235,17 @@ module ActiveModelSerializers
|
|
231
235
|
@primary = []
|
232
236
|
@included = []
|
233
237
|
@resource_identifiers = Set.new
|
234
|
-
serializers.each { |serializer| process_resource(serializer, true) }
|
235
|
-
serializers.each { |serializer| process_relationships(serializer, @
|
238
|
+
serializers.each { |serializer| process_resource(serializer, true, @include_directive) }
|
239
|
+
serializers.each { |serializer| process_relationships(serializer, @include_directive) }
|
236
240
|
|
237
241
|
[@primary, @included]
|
238
242
|
end
|
239
243
|
|
240
|
-
def process_resource(serializer, primary)
|
244
|
+
def process_resource(serializer, primary, include_slice = {})
|
241
245
|
resource_identifier = ResourceIdentifier.new(serializer, instance_options).as_json
|
242
246
|
return false unless @resource_identifiers.add?(resource_identifier)
|
243
247
|
|
244
|
-
resource_object = resource_object_for(serializer)
|
248
|
+
resource_object = resource_object_for(serializer, include_slice)
|
245
249
|
if primary
|
246
250
|
@primary << resource_object
|
247
251
|
else
|
@@ -251,21 +255,22 @@ module ActiveModelSerializers
|
|
251
255
|
true
|
252
256
|
end
|
253
257
|
|
254
|
-
def process_relationships(serializer,
|
255
|
-
serializer.associations(
|
256
|
-
|
258
|
+
def process_relationships(serializer, include_slice)
|
259
|
+
serializer.associations(include_slice).each do |association|
|
260
|
+
# TODO(BF): Process relationship without evaluating lazy_association
|
261
|
+
process_relationship(association.lazy_association.serializer, include_slice[association.key])
|
257
262
|
end
|
258
263
|
end
|
259
264
|
|
260
|
-
def process_relationship(serializer,
|
265
|
+
def process_relationship(serializer, include_slice)
|
261
266
|
if serializer.respond_to?(:each)
|
262
|
-
serializer.each { |s| process_relationship(s,
|
267
|
+
serializer.each { |s| process_relationship(s, include_slice) }
|
263
268
|
return
|
264
269
|
end
|
265
270
|
return unless serializer && serializer.object
|
266
|
-
return unless process_resource(serializer, false)
|
271
|
+
return unless process_resource(serializer, false, include_slice)
|
267
272
|
|
268
|
-
process_relationships(serializer,
|
273
|
+
process_relationships(serializer, include_slice)
|
269
274
|
end
|
270
275
|
|
271
276
|
# {http://jsonapi.org/format/#document-resource-object-attributes Document Resource Object Attributes}
|
@@ -289,21 +294,9 @@ module ActiveModelSerializers
|
|
289
294
|
end
|
290
295
|
|
291
296
|
# {http://jsonapi.org/format/#document-resource-objects Document Resource Objects}
|
292
|
-
def resource_object_for(serializer)
|
293
|
-
resource_object =
|
294
|
-
resource_object = ResourceIdentifier.new(serializer, instance_options).as_json
|
295
|
-
|
296
|
-
requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
|
297
|
-
attributes = attributes_for(serializer, requested_fields)
|
298
|
-
resource_object[:attributes] = attributes if attributes.any?
|
299
|
-
resource_object
|
300
|
-
end
|
297
|
+
def resource_object_for(serializer, include_slice = {})
|
298
|
+
resource_object = data_for(serializer, include_slice)
|
301
299
|
|
302
|
-
requested_associations = fieldset.fields_for(resource_object[:type]) || '*'
|
303
|
-
relationships = relationships_for(serializer, requested_associations)
|
304
|
-
resource_object[:relationships] = relationships if relationships.any?
|
305
|
-
|
306
|
-
links = links_for(serializer)
|
307
300
|
# toplevel_links
|
308
301
|
# definition:
|
309
302
|
# allOf
|
@@ -317,7 +310,10 @@ module ActiveModelSerializers
|
|
317
310
|
# prs:
|
318
311
|
# https://github.com/rails-api/active_model_serializers/pull/1247
|
319
312
|
# https://github.com/rails-api/active_model_serializers/pull/1018
|
320
|
-
|
313
|
+
if (links = links_for(serializer)).any?
|
314
|
+
resource_object ||= {}
|
315
|
+
resource_object[:links] = links
|
316
|
+
end
|
321
317
|
|
322
318
|
# toplevel_meta
|
323
319
|
# alias meta
|
@@ -327,12 +323,33 @@ module ActiveModelSerializers
|
|
327
323
|
# {
|
328
324
|
# :'git-ref' => 'abc123'
|
329
325
|
# }
|
330
|
-
meta = meta_for(serializer)
|
331
|
-
|
326
|
+
if (meta = meta_for(serializer)).present?
|
327
|
+
resource_object ||= {}
|
328
|
+
resource_object[:meta] = meta
|
329
|
+
end
|
332
330
|
|
333
331
|
resource_object
|
334
332
|
end
|
335
333
|
|
334
|
+
def data_for(serializer, include_slice)
|
335
|
+
data = serializer.fetch(self) do
|
336
|
+
resource_object = ResourceIdentifier.new(serializer, instance_options).as_json
|
337
|
+
break nil if resource_object.nil?
|
338
|
+
|
339
|
+
requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
|
340
|
+
attributes = attributes_for(serializer, requested_fields)
|
341
|
+
resource_object[:attributes] = attributes if attributes.any?
|
342
|
+
resource_object
|
343
|
+
end
|
344
|
+
data.tap do |resource_object|
|
345
|
+
next if resource_object.nil?
|
346
|
+
# NOTE(BF): the attributes are cached above, separately from the relationships, below.
|
347
|
+
requested_associations = fieldset.fields_for(resource_object[:type]) || '*'
|
348
|
+
relationships = relationships_for(serializer, requested_associations, include_slice)
|
349
|
+
resource_object[:relationships] = relationships if relationships.any?
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
336
353
|
# {http://jsonapi.org/format/#document-resource-object-relationships Document Resource Object Relationship}
|
337
354
|
# relationships
|
338
355
|
# definition:
|
@@ -428,17 +445,13 @@ module ActiveModelSerializers
|
|
428
445
|
# id: 'required-id',
|
429
446
|
# meta: meta
|
430
447
|
# }.reject! {|_,v| v.nil? }
|
431
|
-
def relationships_for(serializer, requested_associations)
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
options: association.options,
|
439
|
-
links: association.links,
|
440
|
-
meta: association.meta
|
441
|
-
).as_json
|
448
|
+
def relationships_for(serializer, requested_associations, include_slice)
|
449
|
+
include_directive = JSONAPI::IncludeDirective.new(
|
450
|
+
requested_associations,
|
451
|
+
allow_wildcard: true
|
452
|
+
)
|
453
|
+
serializer.associations(include_directive, include_slice).each_with_object({}) do |association, hash|
|
454
|
+
hash[association.key] = Relationship.new(serializer, instance_options, association).as_json
|
442
455
|
end
|
443
456
|
end
|
444
457
|
|
@@ -467,7 +480,8 @@ module ActiveModelSerializers
|
|
467
480
|
# }.reject! {|_,v| v.nil? }
|
468
481
|
def links_for(serializer)
|
469
482
|
serializer._links.each_with_object({}) do |(name, value), hash|
|
470
|
-
|
483
|
+
result = Link.new(serializer, value).as_json
|
484
|
+
hash[name] = result if result
|
471
485
|
end
|
472
486
|
end
|
473
487
|
|
@@ -5,11 +5,13 @@ module ActiveModelSerializers
|
|
5
5
|
private_constant :ADAPTER_MAP if defined?(private_constant)
|
6
6
|
|
7
7
|
class << self # All methods are class functions
|
8
|
+
# :nocov:
|
8
9
|
def new(*args)
|
9
10
|
fail ArgumentError, 'Adapters inherit from Adapter::Base.' \
|
10
11
|
"Adapter.new called with args: '#{args.inspect}', from" \
|
11
12
|
"'caller[0]'."
|
12
13
|
end
|
14
|
+
# :nocov:
|
13
15
|
|
14
16
|
def configured_adapter
|
15
17
|
lookup(ActiveModelSerializers.config.adapter)
|
@@ -51,6 +53,10 @@ module ActiveModelSerializers
|
|
51
53
|
self
|
52
54
|
end
|
53
55
|
|
56
|
+
def registered_name(adapter_class)
|
57
|
+
ADAPTER_MAP.key adapter_class
|
58
|
+
end
|
59
|
+
|
54
60
|
# @param adapter [String, Symbol, Class] name to fetch adapter by
|
55
61
|
# @return [ActiveModelSerializers::Adapter] subclass of Adapter
|
56
62
|
# @raise [UnknownAdapterError]
|
@@ -36,8 +36,7 @@ module ActiveModelSerializers
|
|
36
36
|
target = is_a?(Module) ? "#{self}." : "#{self.class}#"
|
37
37
|
msg = ["NOTE: #{target}#{name} is deprecated",
|
38
38
|
replacement == :none ? ' with no replacement' : "; use #{replacement} instead",
|
39
|
-
"\n#{target}#{name} called from #{ActiveModelSerializers.location_of_caller.join(
|
40
|
-
]
|
39
|
+
"\n#{target}#{name} called from #{ActiveModelSerializers.location_of_caller.join(':')}"]
|
41
40
|
warn "#{msg.join}."
|
42
41
|
send old, *args, &block
|
43
42
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module ActiveModelSerializers
|
2
|
+
module LookupChain
|
3
|
+
# Standard appending of Serializer to the resource name.
|
4
|
+
#
|
5
|
+
# Example:
|
6
|
+
# Author => AuthorSerializer
|
7
|
+
BY_RESOURCE = lambda do |resource_class, _serializer_class, _namespace|
|
8
|
+
serializer_from(resource_class)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Uses the namespace of the resource to find the serializer
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
# British::Author => British::AuthorSerializer
|
15
|
+
BY_RESOURCE_NAMESPACE = lambda do |resource_class, _serializer_class, _namespace|
|
16
|
+
resource_namespace = namespace_for(resource_class)
|
17
|
+
serializer_name = serializer_from(resource_class)
|
18
|
+
|
19
|
+
"#{resource_namespace}::#{serializer_name}"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Uses the controller namespace of the resource to find the serializer
|
23
|
+
#
|
24
|
+
# Example:
|
25
|
+
# Api::V3::AuthorsController => Api::V3::AuthorSerializer
|
26
|
+
BY_NAMESPACE = lambda do |resource_class, _serializer_class, namespace|
|
27
|
+
resource_name = resource_class_name(resource_class)
|
28
|
+
namespace ? "#{namespace}::#{resource_name}Serializer" : nil
|
29
|
+
end
|
30
|
+
|
31
|
+
# Allows for serializers to be defined in parent serializers
|
32
|
+
# - useful if a relationship only needs a different set of attributes
|
33
|
+
# than if it were rendered independently.
|
34
|
+
#
|
35
|
+
# Example:
|
36
|
+
# class BlogSerializer < ActiveModel::Serializer
|
37
|
+
# class AuthorSerialier < ActiveModel::Serializer
|
38
|
+
# ...
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# belongs_to :author
|
42
|
+
# ...
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# The belongs_to relationship would be rendered with
|
46
|
+
# BlogSerializer::AuthorSerialier
|
47
|
+
BY_PARENT_SERIALIZER = lambda do |resource_class, serializer_class, _namespace|
|
48
|
+
return if serializer_class == ActiveModel::Serializer
|
49
|
+
|
50
|
+
serializer_name = serializer_from(resource_class)
|
51
|
+
"#{serializer_class}::#{serializer_name}"
|
52
|
+
end
|
53
|
+
|
54
|
+
DEFAULT = [
|
55
|
+
BY_PARENT_SERIALIZER,
|
56
|
+
BY_NAMESPACE,
|
57
|
+
BY_RESOURCE_NAMESPACE,
|
58
|
+
BY_RESOURCE
|
59
|
+
].freeze
|
60
|
+
|
61
|
+
module_function
|
62
|
+
|
63
|
+
def namespace_for(klass)
|
64
|
+
klass.name.deconstantize
|
65
|
+
end
|
66
|
+
|
67
|
+
def resource_class_name(klass)
|
68
|
+
klass.name.demodulize
|
69
|
+
end
|
70
|
+
|
71
|
+
def serializer_from_resource_name(name)
|
72
|
+
"#{name}Serializer"
|
73
|
+
end
|
74
|
+
|
75
|
+
def serializer_from(klass)
|
76
|
+
name = resource_class_name(klass)
|
77
|
+
serializer_from_resource_name(name)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|