active_model_serializers 0.9.8 → 0.10.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +646 -59
  3. data/MIT-LICENSE +3 -2
  4. data/README.md +194 -846
  5. data/lib/action_controller/serialization.rb +35 -66
  6. data/lib/active_model/serializable_resource.rb +13 -0
  7. data/lib/active_model/serializer/adapter/attributes.rb +17 -0
  8. data/lib/active_model/serializer/adapter/base.rb +20 -0
  9. data/lib/active_model/serializer/adapter/json.rb +17 -0
  10. data/lib/active_model/serializer/adapter/json_api.rb +17 -0
  11. data/lib/active_model/serializer/adapter/null.rb +17 -0
  12. data/lib/active_model/serializer/adapter.rb +26 -0
  13. data/lib/active_model/serializer/array_serializer.rb +14 -0
  14. data/lib/active_model/serializer/association.rb +55 -40
  15. data/lib/active_model/serializer/attribute.rb +27 -0
  16. data/lib/active_model/serializer/belongs_to_reflection.rb +13 -0
  17. data/lib/active_model/serializer/collection_serializer.rb +99 -0
  18. data/lib/active_model/serializer/concerns/caching.rb +305 -0
  19. data/lib/active_model/serializer/error_serializer.rb +16 -0
  20. data/lib/active_model/serializer/errors_serializer.rb +34 -0
  21. data/lib/active_model/serializer/field.rb +92 -0
  22. data/lib/active_model/serializer/fieldset.rb +33 -0
  23. data/lib/active_model/serializer/has_many_reflection.rb +12 -0
  24. data/lib/active_model/serializer/has_one_reflection.rb +9 -0
  25. data/lib/active_model/serializer/lazy_association.rb +99 -0
  26. data/lib/active_model/serializer/link.rb +23 -0
  27. data/lib/active_model/serializer/lint.rb +152 -0
  28. data/lib/active_model/serializer/null.rb +19 -0
  29. data/lib/active_model/serializer/reflection.rb +212 -0
  30. data/lib/active_model/serializer/version.rb +3 -1
  31. data/lib/active_model/serializer.rb +363 -254
  32. data/lib/active_model_serializers/adapter/attributes.rb +36 -0
  33. data/lib/active_model_serializers/adapter/base.rb +85 -0
  34. data/lib/active_model_serializers/adapter/json.rb +23 -0
  35. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +215 -0
  36. data/lib/active_model_serializers/adapter/json_api/error.rb +98 -0
  37. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +51 -0
  38. data/lib/active_model_serializers/adapter/json_api/link.rb +85 -0
  39. data/lib/active_model_serializers/adapter/json_api/meta.rb +39 -0
  40. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +94 -0
  41. data/lib/active_model_serializers/adapter/json_api/relationship.rb +106 -0
  42. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +68 -0
  43. data/lib/active_model_serializers/adapter/json_api.rb +535 -0
  44. data/lib/active_model_serializers/adapter/null.rb +11 -0
  45. data/lib/active_model_serializers/adapter.rb +100 -0
  46. data/lib/active_model_serializers/callbacks.rb +57 -0
  47. data/lib/active_model_serializers/deprecate.rb +56 -0
  48. data/lib/active_model_serializers/deserialization.rb +17 -0
  49. data/lib/active_model_serializers/json_pointer.rb +16 -0
  50. data/lib/active_model_serializers/logging.rb +124 -0
  51. data/lib/active_model_serializers/lookup_chain.rb +82 -0
  52. data/lib/active_model_serializers/model.rb +132 -0
  53. data/lib/active_model_serializers/railtie.rb +62 -0
  54. data/lib/active_model_serializers/register_jsonapi_renderer.rb +80 -0
  55. data/lib/active_model_serializers/serializable_resource.rb +84 -0
  56. data/lib/active_model_serializers/serialization_context.rb +41 -0
  57. data/lib/active_model_serializers/test/schema.rb +140 -0
  58. data/lib/active_model_serializers/test/serializer.rb +127 -0
  59. data/lib/active_model_serializers/test.rb +9 -0
  60. data/lib/active_model_serializers.rb +60 -17
  61. data/lib/generators/rails/USAGE +6 -0
  62. data/lib/{active_model/serializer/generators → generators/rails}/resource_override.rb +3 -4
  63. data/lib/{active_model/serializer/generators/serializer → generators/rails}/serializer_generator.rb +6 -5
  64. data/lib/grape/active_model_serializers.rb +18 -0
  65. data/lib/grape/formatters/active_model_serializers.rb +34 -0
  66. data/lib/grape/helpers/active_model_serializers.rb +19 -0
  67. data/lib/tasks/rubocop.rake +60 -0
  68. metadata +249 -157
  69. data/CONTRIBUTING.md +0 -20
  70. data/DESIGN.textile +0 -586
  71. data/lib/action_controller/serialization_test_case.rb +0 -79
  72. data/lib/active_model/array_serializer.rb +0 -68
  73. data/lib/active_model/default_serializer.rb +0 -28
  74. data/lib/active_model/serializable/utils.rb +0 -16
  75. data/lib/active_model/serializable.rb +0 -59
  76. data/lib/active_model/serializer/association/has_many.rb +0 -39
  77. data/lib/active_model/serializer/association/has_one.rb +0 -25
  78. data/lib/active_model/serializer/config.rb +0 -31
  79. data/lib/active_model/serializer/generators/serializer/USAGE +0 -9
  80. data/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb +0 -14
  81. data/lib/active_model/serializer/generators/serializer/templates/controller.rb +0 -93
  82. data/lib/active_model/serializer/railtie.rb +0 -22
  83. data/lib/active_model/serializer_support.rb +0 -5
  84. data/lib/active_model_serializers/model/caching.rb +0 -25
  85. data/test/benchmark/app.rb +0 -60
  86. data/test/benchmark/benchmarking_support.rb +0 -67
  87. data/test/benchmark/bm_active_record.rb +0 -41
  88. data/test/benchmark/setup.rb +0 -75
  89. data/test/benchmark/tmp/miniprofiler/mp_timers_6eqewtfgrhitvq5gqm25 +0 -0
  90. data/test/benchmark/tmp/miniprofiler/mp_timers_8083sx03hu72pxz1a4d0 +0 -0
  91. data/test/benchmark/tmp/miniprofiler/mp_timers_fyz2gsml4z0ph9kpoy1c +0 -0
  92. data/test/benchmark/tmp/miniprofiler/mp_timers_hjry5rc32imd42oxoi48 +0 -0
  93. data/test/benchmark/tmp/miniprofiler/mp_timers_m8fpoz2cvt3g9agz0bs3 +0 -0
  94. data/test/benchmark/tmp/miniprofiler/mp_timers_p92m2drnj1i568u3sta0 +0 -0
  95. data/test/benchmark/tmp/miniprofiler/mp_timers_qg52tpca3uesdfguee9i +0 -0
  96. data/test/benchmark/tmp/miniprofiler/mp_timers_s15t1a6mvxe0z7vjv790 +0 -0
  97. data/test/benchmark/tmp/miniprofiler/mp_timers_x8kal3d17nfds6vp4kcj +0 -0
  98. data/test/benchmark/tmp/miniprofiler/mp_views_127.0.0.1 +0 -0
  99. data/test/fixtures/active_record.rb +0 -96
  100. data/test/fixtures/poro.rb +0 -223
  101. data/test/fixtures/template.html.erb +0 -1
  102. data/test/integration/action_controller/namespaced_serialization_test.rb +0 -105
  103. data/test/integration/action_controller/serialization_test.rb +0 -287
  104. data/test/integration/action_controller/serialization_test_case_test.rb +0 -71
  105. data/test/integration/active_record/active_record_test.rb +0 -94
  106. data/test/integration/generators/resource_generator_test.rb +0 -26
  107. data/test/integration/generators/scaffold_controller_generator_test.rb +0 -64
  108. data/test/integration/generators/serializer_generator_test.rb +0 -41
  109. data/test/test_app.rb +0 -14
  110. data/test/test_helper.rb +0 -24
  111. data/test/tmp/app/assets/javascripts/accounts.js +0 -2
  112. data/test/tmp/app/assets/stylesheets/accounts.css +0 -4
  113. data/test/tmp/app/controllers/accounts_controller.rb +0 -2
  114. data/test/tmp/app/helpers/accounts_helper.rb +0 -2
  115. data/test/tmp/app/serializers/account_serializer.rb +0 -3
  116. data/test/tmp/config/routes.rb +0 -1
  117. data/test/unit/active_model/array_serializer/except_test.rb +0 -18
  118. data/test/unit/active_model/array_serializer/key_format_test.rb +0 -18
  119. data/test/unit/active_model/array_serializer/meta_test.rb +0 -53
  120. data/test/unit/active_model/array_serializer/only_test.rb +0 -18
  121. data/test/unit/active_model/array_serializer/options_test.rb +0 -16
  122. data/test/unit/active_model/array_serializer/root_test.rb +0 -102
  123. data/test/unit/active_model/array_serializer/scope_test.rb +0 -24
  124. data/test/unit/active_model/array_serializer/serialization_test.rb +0 -216
  125. data/test/unit/active_model/default_serializer_test.rb +0 -13
  126. data/test/unit/active_model/serializer/associations/build_serializer_test.rb +0 -36
  127. data/test/unit/active_model/serializer/associations_test.rb +0 -49
  128. data/test/unit/active_model/serializer/attributes_test.rb +0 -57
  129. data/test/unit/active_model/serializer/config_test.rb +0 -91
  130. data/test/unit/active_model/serializer/filter_test.rb +0 -69
  131. data/test/unit/active_model/serializer/has_many_polymorphic_test.rb +0 -189
  132. data/test/unit/active_model/serializer/has_many_test.rb +0 -265
  133. data/test/unit/active_model/serializer/has_one_and_has_many_test.rb +0 -27
  134. data/test/unit/active_model/serializer/has_one_polymorphic_test.rb +0 -196
  135. data/test/unit/active_model/serializer/has_one_test.rb +0 -253
  136. data/test/unit/active_model/serializer/key_format_test.rb +0 -25
  137. data/test/unit/active_model/serializer/meta_test.rb +0 -39
  138. data/test/unit/active_model/serializer/options_test.rb +0 -42
  139. data/test/unit/active_model/serializer/root_test.rb +0 -117
  140. data/test/unit/active_model/serializer/scope_test.rb +0 -49
  141. data/test/unit/active_model/serializer/url_helpers_test.rb +0 -35
  142. data/test/unit/active_model/serilizable_test.rb +0 -50
  143. /data/lib/{active_model/serializer/generators/serializer/templates/serializer.rb → generators/rails/templates/serializer.rb.erb} +0 -0
@@ -1,64 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/core_ext/class/attribute'
4
+ require 'active_model_serializers/serialization_context'
2
5
 
3
6
  module ActionController
4
- # Action Controller Serialization
5
- #
6
- # Overrides render :json to check if the given object implements +active_model_serializer+
7
- # as a method. If so, use the returned serializer instead of calling +to_json+ on the object.
8
- #
9
- # This module also provides a serialization_scope method that allows you to configure the
10
- # +serialization_scope+ of the serializer. Most apps will likely set the +serialization_scope+
11
- # to the current user:
12
- #
13
- # class ApplicationController < ActionController::Base
14
- # serialization_scope :current_user
15
- # end
16
- #
17
- # If you need more complex scope rules, you can simply override the serialization_scope:
18
- #
19
- # class ApplicationController < ActionController::Base
20
- # private
21
- #
22
- # def serialization_scope
23
- # current_user
24
- # end
25
- # end
26
- #
27
7
  module Serialization
28
8
  extend ActiveSupport::Concern
29
9
 
30
10
  include ActionController::Renderers
31
11
 
32
- class << self
33
- attr_accessor :enabled
34
- end
35
- self.enabled = true
36
-
37
- included do
38
- class_attribute :_serialization_scope
39
- self._serialization_scope = :current_user
40
- end
41
-
42
12
  module ClassMethods
43
13
  def serialization_scope(scope)
44
14
  self._serialization_scope = scope
45
15
  end
46
16
  end
47
17
 
48
- [:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
49
- define_method renderer_method do |resource, options|
50
- serializer = build_json_serializer(resource, options)
18
+ included do
19
+ class_attribute :_serialization_scope
20
+ self._serialization_scope = :current_user
51
21
 
52
- if serializer
53
- super(serializer, options)
54
- else
55
- super(resource, options)
56
- end
57
- end
22
+ attr_writer :namespace_for_serializer
58
23
  end
59
24
 
60
- private
61
-
62
25
  def namespace_for_serializer
63
26
  @namespace_for_serializer ||= namespace_for_class(self.class) unless namespace_for_class(self.class) == Object
64
27
  end
@@ -71,36 +34,42 @@ module ActionController
71
34
  end
72
35
  end
73
36
 
74
- def default_serializer(resource)
75
- options = {}.tap do |o|
76
- o[:namespace] = namespace_for_serializer if namespace_for_serializer
77
- end
37
+ def serialization_scope
38
+ return unless _serialization_scope && respond_to?(_serialization_scope, true)
78
39
 
79
- ActiveModel::Serializer.serializer_for(resource, options)
40
+ send(_serialization_scope)
80
41
  end
81
42
 
82
- def default_serializer_options
83
- {}
84
- end
43
+ def get_serializer(resource, options = {})
44
+ unless use_adapter?
45
+ warn 'ActionController::Serialization#use_adapter? has been removed. '\
46
+ "Please pass 'adapter: false' or see ActiveSupport::SerializableResource.new"
47
+ options[:adapter] = false
48
+ end
85
49
 
86
- def serialization_scope
87
- _serialization_scope = self.class._serialization_scope
88
- send(_serialization_scope) if _serialization_scope && respond_to?(_serialization_scope, true)
89
- end
50
+ options.fetch(:namespace) { options[:namespace] = namespace_for_serializer }
90
51
 
91
- def build_json_serializer(resource, options = {})
92
- options = default_serializer_options.merge(options)
93
- @namespace_for_serializer = options.fetch(:namespace, nil)
52
+ serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)
53
+ serializable_resource.serialization_scope ||= options.fetch(:scope) { serialization_scope }
54
+ serializable_resource.serialization_scope_name = options.fetch(:scope_name) { _serialization_scope }
55
+ # For compatibility with the JSON renderer: `json.to_json(options) if json.is_a?(String)`.
56
+ # Otherwise, since `serializable_resource` is not a string, the renderer would call
57
+ # `to_json` on a String and given odd results, such as `"".to_json #=> '""'`
58
+ serializable_resource.adapter.is_a?(String) ? serializable_resource.adapter : serializable_resource
59
+ end
94
60
 
95
- if serializer = options.fetch(:serializer, default_serializer(resource))
96
- options[:scope] = serialization_scope unless options.has_key?(:scope)
61
+ # Deprecated
62
+ def use_adapter?
63
+ true
64
+ end
97
65
 
98
- if resource.respond_to?(:to_ary)
99
- options[:resource_name] = controller_name
100
- options[:namespace] = namespace_for_serializer if namespace_for_serializer
66
+ [:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
67
+ define_method renderer_method do |resource, options|
68
+ options.fetch(:serialization_context) do
69
+ options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request, options)
101
70
  end
102
-
103
- serializer.new(resource, options)
71
+ serializable_resource = get_serializer(resource, options)
72
+ super(serializable_resource, options)
104
73
  end
105
74
  end
106
75
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module ActiveModel
6
+ class SerializableResource
7
+ class << self
8
+ extend ActiveModelSerializers::Deprecate
9
+
10
+ delegate_and_deprecate :new, ActiveModelSerializers::SerializableResource
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ module Adapter
6
+ class Attributes < DelegateClass(ActiveModelSerializers::Adapter::Attributes)
7
+ def initialize(serializer, options = {})
8
+ super(ActiveModelSerializers::Adapter::Attributes.new(serializer, options))
9
+ end
10
+ class << self
11
+ extend ActiveModelSerializers::Deprecate
12
+ deprecate :new, 'ActiveModelSerializers::Adapter::Json.'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ module Adapter
6
+ class Base < DelegateClass(ActiveModelSerializers::Adapter::Base)
7
+ class << self
8
+ extend ActiveModelSerializers::Deprecate
9
+ deprecate :inherited, 'ActiveModelSerializers::Adapter::Base.'
10
+ end
11
+
12
+ # :nocov:
13
+ def initialize(serializer, options = {})
14
+ super(ActiveModelSerializers::Adapter::Base.new(serializer, options))
15
+ end
16
+ # :nocov:
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ module Adapter
6
+ class Json < DelegateClass(ActiveModelSerializers::Adapter::Json)
7
+ def initialize(serializer, options = {})
8
+ super(ActiveModelSerializers::Adapter::Json.new(serializer, options))
9
+ end
10
+ class << self
11
+ extend ActiveModelSerializers::Deprecate
12
+ deprecate :new, 'ActiveModelSerializers::Adapter::Json.new'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ module Adapter
6
+ class JsonApi < DelegateClass(ActiveModelSerializers::Adapter::JsonApi)
7
+ def initialize(serializer, options = {})
8
+ super(ActiveModelSerializers::Adapter::JsonApi.new(serializer, options))
9
+ end
10
+ class << self
11
+ extend ActiveModelSerializers::Deprecate
12
+ deprecate :new, 'ActiveModelSerializers::Adapter::JsonApi.new'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ module Adapter
6
+ class Null < DelegateClass(ActiveModelSerializers::Adapter::Null)
7
+ def initialize(serializer, options = {})
8
+ super(ActiveModelSerializers::Adapter::Null.new(serializer, options))
9
+ end
10
+ class << self
11
+ extend ActiveModelSerializers::Deprecate
12
+ deprecate :new, 'ActiveModelSerializers::Adapter::Null.new'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model_serializers/adapter'
4
+ require 'active_model_serializers/deprecate'
5
+
6
+ module ActiveModel
7
+ class Serializer
8
+ # @deprecated Use ActiveModelSerializers::Adapter instead
9
+ module Adapter
10
+ class << self
11
+ extend ActiveModelSerializers::Deprecate
12
+
13
+ DEPRECATED_METHODS = [:create, :adapter_class, :adapter_map, :adapters, :register, :lookup].freeze
14
+ DEPRECATED_METHODS.each do |method|
15
+ delegate_and_deprecate method, ActiveModelSerializers::Adapter
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ require 'active_model/serializer/adapter/base'
23
+ require 'active_model/serializer/adapter/null'
24
+ require 'active_model/serializer/adapter/attributes'
25
+ require 'active_model/serializer/adapter/json'
26
+ require 'active_model/serializer/adapter/json_api'
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model/serializer/collection_serializer'
4
+
5
+ module ActiveModel
6
+ class Serializer
7
+ class ArraySerializer < CollectionSerializer
8
+ class << self
9
+ extend ActiveModelSerializers::Deprecate
10
+ deprecate :new, 'ActiveModel::Serializer::CollectionSerializer.'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,58 +1,73 @@
1
- require 'active_model/default_serializer'
2
- require 'active_model/serializer/association/has_one'
3
- require 'active_model/serializer/association/has_many'
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model/serializer/lazy_association'
4
4
 
5
5
  module ActiveModel
6
6
  class Serializer
7
- class Association
8
- def initialize(name, options={})
9
- if options.has_key?(:include)
10
- ActiveSupport::Deprecation.warn <<-WARN
11
- ** Notice: include was renamed to embed_in_root. **
12
- WARN
13
- end
7
+ # This class holds all information about serializer's association.
8
+ #
9
+ # @api private
10
+ Association = Struct.new(:reflection, :association_options) do
11
+ attr_reader :lazy_association
12
+ delegate :object, :include_data?, :virtual_value, :collection?, to: :lazy_association
13
+
14
+ def initialize(*)
15
+ super
16
+ @lazy_association = LazyAssociation.new(reflection, association_options)
17
+ end
14
18
 
15
- @name = name.to_s
16
- @options = options
17
- self.embed = options.fetch(:embed) { CONFIG.embed }
18
- @polymorphic = options.fetch(:polymorphic, false)
19
- @embed_in_root = options.fetch(:embed_in_root) { options.fetch(:include) { CONFIG.embed_in_root } }
20
- @key_format = options.fetch(:key_format) { CONFIG.key_format }
21
- @embed_key = options[:embed_key] || :id
22
- @key = options[:key]
23
- @embedded_key = options[:root] || name
24
- @embed_in_root_key = options.fetch(:embed_in_root_key) { CONFIG.embed_in_root_key }
25
- @embed_namespace = options.fetch(:embed_namespace) { CONFIG.embed_namespace }
19
+ # @return [Symbol]
20
+ delegate :name, to: :reflection
26
21
 
27
- serializer = @options[:serializer]
28
- @serializer_from_options = serializer.is_a?(String) ? serializer.constantize : serializer
22
+ # @return [Symbol]
23
+ def key
24
+ reflection_options.fetch(:key, name)
29
25
  end
30
26
 
31
- attr_reader :name, :embed_ids, :embed_objects, :polymorphic
32
- attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :root_key, :serializer_from_options, :options, :key_format, :embed_in_root_key, :embed_namespace
33
- alias embed_ids? embed_ids
34
- alias embed_objects? embed_objects
35
- alias embed_in_root? embed_in_root
36
- alias embed_in_root_key? embed_in_root_key
37
- alias embed_namespace? embed_namespace
38
- alias polymorphic? polymorphic
27
+ # @return [True,False]
28
+ def key?
29
+ reflection_options.key?(:key)
30
+ end
39
31
 
40
- def embed=(embed)
41
- @embed_ids = embed == :id || embed == :ids
42
- @embed_objects = embed == :object || embed == :objects
32
+ # @return [Hash]
33
+ def links
34
+ reflection_options.fetch(:links) || {}
43
35
  end
44
36
 
45
- def serializer_from_object(object, options = {})
46
- Serializer.serializer_for(object, options)
37
+ # @return [Hash, nil]
38
+ # This gets mutated, so cannot use the cached reflection_options
39
+ def meta
40
+ reflection.options[:meta]
47
41
  end
48
42
 
49
- def default_serializer
50
- DefaultSerializer
43
+ def belongs_to?
44
+ reflection.foreign_key_on == :self
51
45
  end
52
46
 
53
- def build_serializer(object, options = {})
54
- serializer_class(object, options).new(object, options.merge(self.options))
47
+ def polymorphic?
48
+ true == reflection_options[:polymorphic]
55
49
  end
50
+
51
+ # @api private
52
+ def serializable_hash(adapter_options, adapter_instance)
53
+ association_serializer = lazy_association.serializer
54
+ return virtual_value if virtual_value
55
+ association_object = association_serializer && association_serializer.object
56
+ return unless association_object
57
+
58
+ serialization = association_serializer.serializable_hash(adapter_options, {}, adapter_instance)
59
+
60
+ if polymorphic? && serialization
61
+ polymorphic_type = association_object.class.name.underscore
62
+ serialization = { type: polymorphic_type, polymorphic_type.to_sym => serialization }
63
+ end
64
+
65
+ serialization
66
+ end
67
+
68
+ private
69
+
70
+ delegate :reflection_options, to: :lazy_association
56
71
  end
57
72
  end
58
73
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model/serializer/field'
4
+
5
+ module ActiveModel
6
+ class Serializer
7
+ # Holds all the meta-data about an attribute as it was specified in the
8
+ # ActiveModel::Serializer class.
9
+ #
10
+ # @example
11
+ # class PostSerializer < ActiveModel::Serializer
12
+ # attribute :content
13
+ # attribute :name, key: :title
14
+ # attribute :email, key: :author_email, if: :user_logged_in?
15
+ # attribute :preview do
16
+ # truncate(object.content)
17
+ # end
18
+ #
19
+ # def user_logged_in?
20
+ # current_user.logged_in?
21
+ # end
22
+ # end
23
+ #
24
+ class Attribute < Field
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ # @api private
6
+ class BelongsToReflection < Reflection
7
+ # @api private
8
+ def foreign_key_on
9
+ :self
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class CollectionSerializer
6
+ include Enumerable
7
+ delegate :each, to: :@serializers
8
+
9
+ attr_reader :object, :root
10
+
11
+ def initialize(resources, options = {})
12
+ @object = resources
13
+ @options = options
14
+ @root = options[:root]
15
+ @serializers = serializers_from_resources
16
+ end
17
+
18
+ def success?
19
+ true
20
+ end
21
+
22
+ # @api private
23
+ def serializable_hash(adapter_options, options, adapter_instance)
24
+ options[:include_directive] ||= ActiveModel::Serializer.include_directive_from_options(adapter_options)
25
+ options[:cached_attributes] ||= ActiveModel::Serializer.cache_read_multi(self, adapter_instance, options[:include_directive])
26
+ serializers.map do |serializer|
27
+ serializer.serializable_hash(adapter_options, options, adapter_instance)
28
+ end
29
+ end
30
+
31
+ # TODO: unify naming of root, json_key, and _type. Right now, a serializer's
32
+ # json_key comes from the root option or the object's model name, by default.
33
+ # But, if a dev defines a custom `json_key` method with an explicit value,
34
+ # we have no simple way to know that it is safe to call that instance method.
35
+ # (which is really a class property at this point, anyhow).
36
+ # rubocop:disable Metrics/CyclomaticComplexity
37
+ # Disabling cop since it's good to highlight the complexity of this method by
38
+ # including all the logic right here.
39
+ def json_key
40
+ return root if root
41
+ # 1. get from options[:serializer] for empty resource collection
42
+ key = object.empty? &&
43
+ (explicit_serializer_class = options[:serializer]) &&
44
+ explicit_serializer_class._type
45
+ # 2. get from first serializer instance in collection
46
+ key ||= (serializer = serializers.first) && serializer.json_key
47
+ # 3. get from collection name, if a named collection
48
+ key ||= object.respond_to?(:name) ? object.name && object.name.underscore : nil
49
+ # 4. key may be nil for empty collection and no serializer option
50
+ key &&= key.pluralize
51
+ if raise_cannot_infer_root_key_error?
52
+ # 5. fail if the key cannot be determined
53
+ key || fail(CannotInferRootKeyError, 'Cannot infer root key from collection type. Please specify the root or each_serializer option, or render a JSON String')
54
+ end
55
+ key
56
+ end
57
+ # rubocop:enable Metrics/CyclomaticComplexity
58
+
59
+ def paginated?
60
+ ActiveModelSerializers.config.jsonapi_pagination_links_enabled &&
61
+ object.respond_to?(:current_page) &&
62
+ object.respond_to?(:total_pages) &&
63
+ object.respond_to?(:size)
64
+ end
65
+
66
+ class CannotInferRootKeyError < StandardError; end
67
+
68
+ protected
69
+
70
+ attr_reader :serializers, :options
71
+
72
+ private
73
+
74
+ def raise_cannot_infer_root_key_error?
75
+ ActiveModelSerializers.config.raise_cannot_infer_root_key_error
76
+ end
77
+
78
+ def serializers_from_resources
79
+ serializer_context_class = options.fetch(:serializer_context_class, ActiveModel::Serializer)
80
+ object.map do |resource|
81
+ serializer_from_resource(resource, serializer_context_class, options)
82
+ end
83
+ end
84
+
85
+ def serializer_from_resource(resource, serializer_context_class, options)
86
+ serializer_class = options.fetch(:serializer) do
87
+ serializer_context_class.serializer_for(resource, namespace: options[:namespace])
88
+ end
89
+
90
+ if serializer_class.nil?
91
+ ActiveModelSerializers.logger.debug "No serializer found for resource: #{resource.inspect}"
92
+ throw :no_serializer
93
+ else
94
+ serializer_class.new(resource, options.except(:serializer))
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end