active_model_serializers 0.9.12 → 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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +638 -82
  3. data/MIT-LICENSE +3 -2
  4. data/README.md +194 -846
  5. data/lib/action_controller/serialization.rb +34 -74
  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 +53 -38
  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 +1 -1
  31. data/lib/active_model/serializer.rb +361 -263
  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 +58 -27
  61. data/lib/generators/rails/USAGE +6 -0
  62. data/lib/{active_model/serializer/generators → generators/rails}/resource_override.rb +1 -4
  63. data/lib/{active_model/serializer/generators/serializer → generators/rails}/serializer_generator.rb +4 -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 +248 -155
  69. data/CONTRIBUTING.md +0 -20
  70. data/DESIGN.textile +0 -586
  71. data/lib/action_controller/serialization_test_case.rb +0 -82
  72. data/lib/active_model/array_serializer.rb +0 -70
  73. data/lib/active_model/default_serializer.rb +0 -30
  74. data/lib/active_model/serializable/utils.rb +0 -18
  75. data/lib/active_model/serializable.rb +0 -61
  76. data/lib/active_model/serializer/association/has_many.rb +0 -41
  77. data/lib/active_model/serializer/association/has_one.rb +0 -27
  78. data/lib/active_model/serializer/config.rb +0 -33
  79. data/lib/active_model/serializer/generators/serializer/USAGE +0 -9
  80. data/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb +0 -16
  81. data/lib/active_model/serializer/generators/serializer/templates/controller.rb +0 -93
  82. data/lib/active_model/serializer/railtie.rb +0 -24
  83. data/lib/active_model/serializer_support.rb +0 -7
  84. data/test/benchmark/app.rb +0 -60
  85. data/test/benchmark/benchmarking_support.rb +0 -67
  86. data/test/benchmark/bm_active_record.rb +0 -41
  87. data/test/benchmark/setup.rb +0 -75
  88. data/test/benchmark/tmp/miniprofiler/mp_timers_6eqewtfgrhitvq5gqm25 +0 -0
  89. data/test/benchmark/tmp/miniprofiler/mp_timers_8083sx03hu72pxz1a4d0 +0 -0
  90. data/test/benchmark/tmp/miniprofiler/mp_timers_fyz2gsml4z0ph9kpoy1c +0 -0
  91. data/test/benchmark/tmp/miniprofiler/mp_timers_hjry5rc32imd42oxoi48 +0 -0
  92. data/test/benchmark/tmp/miniprofiler/mp_timers_m8fpoz2cvt3g9agz0bs3 +0 -0
  93. data/test/benchmark/tmp/miniprofiler/mp_timers_p92m2drnj1i568u3sta0 +0 -0
  94. data/test/benchmark/tmp/miniprofiler/mp_timers_qg52tpca3uesdfguee9i +0 -0
  95. data/test/benchmark/tmp/miniprofiler/mp_timers_s15t1a6mvxe0z7vjv790 +0 -0
  96. data/test/benchmark/tmp/miniprofiler/mp_timers_x8kal3d17nfds6vp4kcj +0 -0
  97. data/test/benchmark/tmp/miniprofiler/mp_views_127.0.0.1 +0 -0
  98. data/test/fixtures/active_record.rb +0 -96
  99. data/test/fixtures/poro.rb +0 -255
  100. data/test/fixtures/template.html.erb +0 -1
  101. data/test/integration/action_controller/namespaced_serialization_test.rb +0 -105
  102. data/test/integration/action_controller/serialization_test.rb +0 -287
  103. data/test/integration/action_controller/serialization_test_case_test.rb +0 -71
  104. data/test/integration/active_record/active_record_test.rb +0 -94
  105. data/test/integration/generators/resource_generator_test.rb +0 -26
  106. data/test/integration/generators/scaffold_controller_generator_test.rb +0 -64
  107. data/test/integration/generators/serializer_generator_test.rb +0 -41
  108. data/test/test_app.rb +0 -18
  109. data/test/test_helper.rb +0 -31
  110. data/test/tmp/app/assets/javascripts/accounts.js +0 -2
  111. data/test/tmp/app/assets/stylesheets/accounts.css +0 -4
  112. data/test/tmp/app/controllers/accounts_controller.rb +0 -3
  113. data/test/tmp/app/helpers/accounts_helper.rb +0 -3
  114. data/test/tmp/app/serializers/account_serializer.rb +0 -4
  115. data/test/tmp/config/routes.rb +0 -2
  116. data/test/unit/active_model/array_serializer/except_test.rb +0 -18
  117. data/test/unit/active_model/array_serializer/key_format_test.rb +0 -18
  118. data/test/unit/active_model/array_serializer/meta_test.rb +0 -53
  119. data/test/unit/active_model/array_serializer/only_test.rb +0 -18
  120. data/test/unit/active_model/array_serializer/options_test.rb +0 -16
  121. data/test/unit/active_model/array_serializer/root_test.rb +0 -102
  122. data/test/unit/active_model/array_serializer/scope_test.rb +0 -24
  123. data/test/unit/active_model/array_serializer/serialization_test.rb +0 -239
  124. data/test/unit/active_model/default_serializer_test.rb +0 -13
  125. data/test/unit/active_model/serializer/associations/build_serializer_test.rb +0 -36
  126. data/test/unit/active_model/serializer/associations_test.rb +0 -49
  127. data/test/unit/active_model/serializer/attributes_test.rb +0 -57
  128. data/test/unit/active_model/serializer/config_test.rb +0 -91
  129. data/test/unit/active_model/serializer/filter_test.rb +0 -69
  130. data/test/unit/active_model/serializer/has_many_polymorphic_test.rb +0 -189
  131. data/test/unit/active_model/serializer/has_many_test.rb +0 -265
  132. data/test/unit/active_model/serializer/has_one_and_has_many_test.rb +0 -27
  133. data/test/unit/active_model/serializer/has_one_polymorphic_test.rb +0 -196
  134. data/test/unit/active_model/serializer/has_one_test.rb +0 -253
  135. data/test/unit/active_model/serializer/key_format_test.rb +0 -25
  136. data/test/unit/active_model/serializer/meta_test.rb +0 -39
  137. data/test/unit/active_model/serializer/options_test.rb +0 -42
  138. data/test/unit/active_model/serializer/root_test.rb +0 -117
  139. data/test/unit/active_model/serializer/scope_test.rb +0 -49
  140. data/test/unit/active_model/serializer/url_helpers_test.rb +0 -36
  141. data/test/unit/active_model/serilizable_test.rb +0 -50
  142. /data/lib/{active_model/serializer/generators/serializer/templates/serializer.rb → generators/rails/templates/serializer.rb.erb} +0 -0
@@ -1,75 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'active_support/core_ext/class/attribute'
4
+ require 'active_model_serializers/serialization_context'
4
5
 
5
6
  module ActionController
6
- # Action Controller Serialization
7
- #
8
- # Overrides render :json to check if the given object implements +active_model_serializer+
9
- # as a method. If so, use the returned serializer instead of calling +to_json+ on the object.
10
- #
11
- # This module also provides a serialization_scope method that allows you to configure the
12
- # +serialization_scope+ of the serializer. Most apps will likely set the +serialization_scope+
13
- # to the current user:
14
- #
15
- # class ApplicationController < ActionController::Base
16
- # serialization_scope :current_user
17
- # end
18
- #
19
- # If you need more complex scope rules, you can simply override the serialization_scope:
20
- #
21
- # class ApplicationController < ActionController::Base
22
- # private
23
- #
24
- # def serialization_scope
25
- # current_user
26
- # end
27
- # end
28
- #
29
7
  module Serialization
30
8
  extend ActiveSupport::Concern
31
9
 
32
10
  include ActionController::Renderers
33
11
 
34
- class << self
35
- attr_accessor :enabled
36
- end
37
- self.enabled = true
38
-
39
- included do
40
- class_attribute :_serialization_scope
41
- self._serialization_scope = :current_user
42
- end
43
-
44
12
  module ClassMethods
45
13
  def serialization_scope(scope)
46
14
  self._serialization_scope = scope
47
15
  end
48
16
  end
49
17
 
50
- def initialize(*)
51
- super
52
- @namespace_for_serializer = nil
53
- end
54
- ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
55
-
56
- [:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
57
- define_method renderer_method do |resource, options|
58
- serializer = build_json_serializer(resource, options)
18
+ included do
19
+ class_attribute :_serialization_scope
20
+ self._serialization_scope = :current_user
59
21
 
60
- if serializer
61
- super(serializer, options)
62
- else
63
- super(resource, options)
64
- end
65
- end
22
+ attr_writer :namespace_for_serializer
66
23
  end
67
24
 
68
- private
69
-
70
25
  def namespace_for_serializer
71
- @namespace_for_serializer ||= namespace_for_class(self.class)
72
- @namespace_for_serializer unless @namespace_for_serializer == Object
26
+ @namespace_for_serializer ||= namespace_for_class(self.class) unless namespace_for_class(self.class) == Object
73
27
  end
74
28
 
75
29
  def namespace_for_class(klass)
@@ -80,36 +34,42 @@ module ActionController
80
34
  end
81
35
  end
82
36
 
83
- def default_serializer(resource)
84
- options = {}.tap do |o|
85
- o[:namespace] = namespace_for_serializer if namespace_for_serializer
86
- end
37
+ def serialization_scope
38
+ return unless _serialization_scope && respond_to?(_serialization_scope, true)
87
39
 
88
- ActiveModel::Serializer.serializer_for(resource, options)
40
+ send(_serialization_scope)
89
41
  end
90
42
 
91
- def default_serializer_options
92
- {}
93
- 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
94
49
 
95
- def serialization_scope
96
- _serialization_scope = self.class._serialization_scope
97
- send(_serialization_scope) if _serialization_scope && respond_to?(_serialization_scope, true)
98
- end
50
+ options.fetch(:namespace) { options[:namespace] = namespace_for_serializer }
99
51
 
100
- def build_json_serializer(resource, options = {})
101
- options = default_serializer_options.merge(options)
102
- @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
103
60
 
104
- if serializer = options.fetch(:serializer, default_serializer(resource))
105
- options[:scope] = serialization_scope unless options.has_key?(:scope)
61
+ # Deprecated
62
+ def use_adapter?
63
+ true
64
+ end
106
65
 
107
- if resource.respond_to?(:to_ary)
108
- options[:resource_name] = controller_name
109
- 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)
110
70
  end
111
-
112
- serializer.new(resource, options)
71
+ serializable_resource = get_serializer(resource, options)
72
+ super(serializable_resource, options)
113
73
  end
114
74
  end
115
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
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_model/default_serializer'
4
- require 'active_model/serializer/association/has_one'
5
- require 'active_model/serializer/association/has_many'
3
+ require 'active_model/serializer/lazy_association'
6
4
 
7
5
  module ActiveModel
8
6
  class Serializer
9
- class Association
10
- def initialize(name, options={})
11
- if options.has_key?(:include)
12
- ActiveSupport::Deprecation.warn("** Notice: include was renamed to embed_in_root. **")
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
31
+
32
+ # @return [Hash]
33
+ def links
34
+ reflection_options.fetch(:links) || {}
35
+ end
39
36
 
40
- def embed=(embed)
41
- @embed_ids = embed == :id || embed == :ids
42
- @embed_objects = embed == :object || embed == :objects
37
+ # @return [Hash, nil]
38
+ # This gets mutated, so cannot use the cached reflection_options
39
+ def meta
40
+ reflection.options[:meta]
43
41
  end
44
42
 
45
- def serializer_from_object(object, options = {})
46
- Serializer.serializer_for(object, options)
43
+ def belongs_to?
44
+ reflection.foreign_key_on == :self
47
45
  end
48
46
 
49
- def default_serializer
50
- DefaultSerializer
47
+ def polymorphic?
48
+ true == reflection_options[:polymorphic]
51
49
  end
52
50
 
53
- def build_serializer(object, options = {})
54
- serializer_class(object, options).new(object, options.merge(self.options))
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
55
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