active_model_serializers 0.10.0.rc4 → 0.10.0.rc5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +29 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +19 -1
  6. data/.rubocop_todo.yml +30 -103
  7. data/.simplecov +0 -1
  8. data/.travis.yml +20 -8
  9. data/CHANGELOG.md +89 -5
  10. data/CONTRIBUTING.md +54 -179
  11. data/Gemfile +7 -2
  12. data/{LICENSE.txt → MIT-LICENSE} +0 -0
  13. data/README.md +27 -5
  14. data/Rakefile +44 -16
  15. data/active_model_serializers.gemspec +9 -1
  16. data/appveyor.yml +1 -0
  17. data/bin/bench +171 -0
  18. data/bin/bench_regression +316 -0
  19. data/bin/serve_benchmark +39 -0
  20. data/docs/ARCHITECTURE.md +13 -7
  21. data/docs/README.md +5 -1
  22. data/docs/STYLE.md +58 -0
  23. data/docs/general/adapters.md +99 -16
  24. data/docs/general/configuration_options.md +87 -14
  25. data/docs/general/deserialization.md +100 -0
  26. data/docs/general/getting_started.md +35 -0
  27. data/docs/general/instrumentation.md +1 -1
  28. data/docs/general/key_transforms.md +40 -0
  29. data/docs/general/rendering.md +115 -13
  30. data/docs/general/serializers.md +138 -6
  31. data/docs/howto/add_pagination_links.md +36 -18
  32. data/docs/howto/outside_controller_use.md +4 -4
  33. data/docs/howto/passing_arbitrary_options.md +27 -0
  34. data/docs/jsonapi/errors.md +56 -0
  35. data/docs/jsonapi/schema.md +29 -18
  36. data/docs/rfcs/0000-namespace.md +106 -0
  37. data/docs/rfcs/template.md +15 -0
  38. data/lib/action_controller/serialization.rb +10 -19
  39. data/lib/active_model/serializable_resource.rb +4 -65
  40. data/lib/active_model/serializer.rb +73 -18
  41. data/lib/active_model/serializer/adapter.rb +15 -82
  42. data/lib/active_model/serializer/adapter/attributes.rb +5 -56
  43. data/lib/active_model/serializer/adapter/base.rb +5 -47
  44. data/lib/active_model/serializer/adapter/json.rb +6 -12
  45. data/lib/active_model/serializer/adapter/json_api.rb +5 -213
  46. data/lib/active_model/serializer/adapter/null.rb +7 -3
  47. data/lib/active_model/serializer/array_serializer.rb +3 -3
  48. data/lib/active_model/serializer/association.rb +4 -5
  49. data/lib/active_model/serializer/attributes.rb +1 -1
  50. data/lib/active_model/serializer/caching.rb +56 -5
  51. data/lib/active_model/serializer/collection_serializer.rb +30 -13
  52. data/lib/active_model/serializer/configuration.rb +7 -0
  53. data/lib/active_model/serializer/error_serializer.rb +10 -0
  54. data/lib/active_model/serializer/errors_serializer.rb +27 -0
  55. data/lib/active_model/serializer/links.rb +4 -2
  56. data/lib/active_model/serializer/lint.rb +14 -0
  57. data/lib/active_model/serializer/meta.rb +29 -0
  58. data/lib/active_model/serializer/null.rb +17 -0
  59. data/lib/active_model/serializer/reflection.rb +57 -1
  60. data/lib/active_model/serializer/type.rb +1 -1
  61. data/lib/active_model/serializer/version.rb +1 -1
  62. data/lib/active_model_serializers.rb +17 -0
  63. data/lib/active_model_serializers/adapter.rb +92 -0
  64. data/lib/active_model_serializers/adapter/attributes.rb +94 -0
  65. data/lib/active_model_serializers/adapter/base.rb +90 -0
  66. data/lib/active_model_serializers/adapter/json.rb +11 -0
  67. data/lib/active_model_serializers/adapter/json_api.rb +513 -0
  68. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +213 -0
  69. data/lib/active_model_serializers/adapter/json_api/error.rb +96 -0
  70. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +49 -0
  71. data/lib/active_model_serializers/adapter/json_api/link.rb +83 -0
  72. data/lib/active_model_serializers/adapter/json_api/meta.rb +37 -0
  73. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +57 -0
  74. data/lib/active_model_serializers/adapter/json_api/relationship.rb +52 -0
  75. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +37 -0
  76. data/lib/active_model_serializers/adapter/null.rb +10 -0
  77. data/lib/active_model_serializers/cached_serializer.rb +87 -0
  78. data/lib/active_model_serializers/callbacks.rb +1 -1
  79. data/lib/active_model_serializers/deprecate.rb +55 -0
  80. data/lib/active_model_serializers/deserialization.rb +2 -2
  81. data/lib/active_model_serializers/fragment_cache.rb +118 -0
  82. data/lib/active_model_serializers/json_pointer.rb +14 -0
  83. data/lib/active_model_serializers/key_transform.rb +70 -0
  84. data/lib/active_model_serializers/logging.rb +4 -1
  85. data/lib/active_model_serializers/model.rb +11 -1
  86. data/lib/active_model_serializers/railtie.rb +9 -1
  87. data/lib/active_model_serializers/register_jsonapi_renderer.rb +64 -0
  88. data/lib/active_model_serializers/serializable_resource.rb +81 -0
  89. data/lib/active_model_serializers/serialization_context.rb +24 -2
  90. data/lib/active_model_serializers/test/schema.rb +2 -2
  91. data/lib/grape/formatters/active_model_serializers.rb +1 -1
  92. data/test/action_controller/adapter_selector_test.rb +1 -1
  93. data/test/action_controller/json_api/deserialization_test.rb +56 -3
  94. data/test/action_controller/json_api/errors_test.rb +41 -0
  95. data/test/action_controller/json_api/linked_test.rb +10 -9
  96. data/test/action_controller/json_api/pagination_test.rb +2 -2
  97. data/test/action_controller/json_api/transform_test.rb +180 -0
  98. data/test/action_controller/serialization_scope_name_test.rb +201 -35
  99. data/test/action_controller/serialization_test.rb +39 -7
  100. data/test/active_model_serializers/adapter_for_test.rb +208 -0
  101. data/test/active_model_serializers/cached_serializer_test.rb +80 -0
  102. data/test/active_model_serializers/fragment_cache_test.rb +34 -0
  103. data/test/active_model_serializers/json_pointer_test.rb +20 -0
  104. data/test/active_model_serializers/key_transform_test.rb +263 -0
  105. data/test/active_model_serializers/logging_test.rb +8 -8
  106. data/test/active_model_serializers/railtie_test_isolated.rb +6 -0
  107. data/test/active_model_serializers/serialization_context_test_isolated.rb +58 -0
  108. data/test/adapter/deprecation_test.rb +100 -0
  109. data/test/adapter/json/belongs_to_test.rb +32 -34
  110. data/test/adapter/json/collection_test.rb +73 -75
  111. data/test/adapter/json/has_many_test.rb +36 -38
  112. data/test/adapter/json/transform_test.rb +93 -0
  113. data/test/adapter/json_api/belongs_to_test.rb +127 -129
  114. data/test/adapter/json_api/collection_test.rb +80 -82
  115. data/test/adapter/json_api/errors_test.rb +78 -0
  116. data/test/adapter/json_api/fields_test.rb +68 -70
  117. data/test/adapter/json_api/has_many_embed_ids_test.rb +32 -34
  118. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +75 -77
  119. data/test/adapter/json_api/has_many_test.rb +121 -123
  120. data/test/adapter/json_api/has_one_test.rb +59 -61
  121. data/test/adapter/json_api/json_api_test.rb +28 -30
  122. data/test/adapter/json_api/linked_test.rb +319 -321
  123. data/test/adapter/json_api/links_test.rb +75 -50
  124. data/test/adapter/json_api/pagination_links_test.rb +115 -82
  125. data/test/adapter/json_api/parse_test.rb +114 -116
  126. data/test/adapter/json_api/relationship_test.rb +161 -0
  127. data/test/adapter/json_api/relationships_test.rb +199 -0
  128. data/test/adapter/json_api/resource_identifier_test.rb +85 -0
  129. data/test/adapter/json_api/resource_meta_test.rb +100 -0
  130. data/test/adapter/json_api/toplevel_jsonapi_test.rb +61 -63
  131. data/test/adapter/json_api/transform_test.rb +500 -0
  132. data/test/adapter/json_api/type_test.rb +61 -0
  133. data/test/adapter/json_test.rb +35 -37
  134. data/test/adapter/null_test.rb +13 -15
  135. data/test/adapter/polymorphic_test.rb +72 -0
  136. data/test/adapter_test.rb +27 -29
  137. data/test/array_serializer_test.rb +7 -8
  138. data/test/benchmark/app.rb +65 -0
  139. data/test/benchmark/benchmarking_support.rb +67 -0
  140. data/test/benchmark/bm_caching.rb +117 -0
  141. data/test/benchmark/bm_transform.rb +34 -0
  142. data/test/benchmark/config.ru +3 -0
  143. data/test/benchmark/controllers.rb +77 -0
  144. data/test/benchmark/fixtures.rb +167 -0
  145. data/test/cache_test.rb +388 -0
  146. data/test/collection_serializer_test.rb +10 -0
  147. data/test/fixtures/active_record.rb +12 -0
  148. data/test/fixtures/poro.rb +28 -3
  149. data/test/grape_test.rb +5 -5
  150. data/test/lint_test.rb +9 -0
  151. data/test/serializable_resource_test.rb +59 -3
  152. data/test/serializers/associations_test.rb +8 -8
  153. data/test/serializers/attribute_test.rb +7 -7
  154. data/test/serializers/caching_configuration_test_isolated.rb +170 -0
  155. data/test/serializers/meta_test.rb +74 -6
  156. data/test/serializers/read_attribute_for_serialization_test.rb +79 -0
  157. data/test/serializers/serialization_test.rb +55 -0
  158. data/test/support/isolated_unit.rb +3 -0
  159. data/test/support/rails5_shims.rb +26 -8
  160. data/test/support/rails_app.rb +38 -18
  161. data/test/support/serialization_testing.rb +5 -5
  162. data/test/test_helper.rb +6 -10
  163. metadata +132 -37
  164. data/docs/DESIGN.textile +7 -1
  165. data/lib/active_model/serializer/adapter/cached_serializer.rb +0 -45
  166. data/lib/active_model/serializer/adapter/fragment_cache.rb +0 -111
  167. data/lib/active_model/serializer/adapter/json/fragment_cache.rb +0 -13
  168. data/lib/active_model/serializer/adapter/json_api/deserialization.rb +0 -207
  169. data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +0 -21
  170. data/lib/active_model/serializer/adapter/json_api/link.rb +0 -44
  171. data/lib/active_model/serializer/adapter/json_api/pagination_links.rb +0 -58
  172. data/test/active_model_serializers/serialization_context_test.rb +0 -18
  173. data/test/adapter/fragment_cache_test.rb +0 -38
  174. data/test/adapter/json_api/resource_type_config_test.rb +0 -71
  175. data/test/serializers/adapter_for_test.rb +0 -166
  176. data/test/serializers/cache_test.rb +0 -209
  177. data/test/support/simplecov.rb +0 -6
  178. data/test/support/stream_capture.rb +0 -50
  179. data/test/support/test_case.rb +0 -19
@@ -1,6 +1,8 @@
1
1
  require 'thread_safe'
2
2
  require 'active_model/serializer/collection_serializer'
3
3
  require 'active_model/serializer/array_serializer'
4
+ require 'active_model/serializer/error_serializer'
5
+ require 'active_model/serializer/errors_serializer'
4
6
  require 'active_model/serializer/include_tree'
5
7
  require 'active_model/serializer/associations'
6
8
  require 'active_model/serializer/attributes'
@@ -9,19 +11,23 @@ require 'active_model/serializer/configuration'
9
11
  require 'active_model/serializer/fieldset'
10
12
  require 'active_model/serializer/lint'
11
13
  require 'active_model/serializer/links'
14
+ require 'active_model/serializer/meta'
12
15
  require 'active_model/serializer/type'
13
16
 
14
17
  # ActiveModel::Serializer is an abstract class that is
15
18
  # reified when subclassed to decorate a resource.
16
19
  module ActiveModel
17
20
  class Serializer
21
+ extend ActiveSupport::Autoload
22
+ autoload :Adapter
23
+ autoload :Null
18
24
  include Configuration
19
25
  include Associations
20
26
  include Attributes
21
27
  include Caching
22
28
  include Links
29
+ include Meta
23
30
  include Type
24
- require 'active_model/serializer/adapter'
25
31
 
26
32
  # @param resource [ActiveRecord::Base, ActiveModelSerializers::Model]
27
33
  # @return [ActiveModel::Serializer]
@@ -40,9 +46,14 @@ module ActiveModel
40
46
  end
41
47
  end
42
48
 
43
- # @see ActiveModel::Serializer::Adapter.lookup
49
+ # @see ActiveModelSerializers::Adapter.lookup
50
+ # Deprecated
44
51
  def self.adapter
45
- ActiveModel::Serializer::Adapter.lookup(config.adapter)
52
+ ActiveModelSerializers::Adapter.lookup(config.adapter)
53
+ end
54
+ class << self
55
+ extend ActiveModelSerializers::Deprecate
56
+ deprecate :adapter, 'ActiveModelSerializers::Adapter.configured_adapter'
46
57
  end
47
58
 
48
59
  # @api private
@@ -67,7 +78,7 @@ module ActiveModel
67
78
 
68
79
  # @api private
69
80
  # Find a serializer from a class and caches the lookup.
70
- # Preferentially retuns:
81
+ # Preferentially returns:
71
82
  # 1. class name appended with "Serializer"
72
83
  # 2. try again with superclass, if present
73
84
  # 3. nil
@@ -85,15 +96,6 @@ module ActiveModel
85
96
  end
86
97
  end
87
98
 
88
- def self._serializer_instance_method_defined?(name)
89
- _serializer_instance_methods.include?(name)
90
- end
91
-
92
- def self._serializer_instance_methods
93
- @_serializer_instance_methods ||= (public_instance_methods - Object.public_instance_methods).to_set
94
- end
95
- private_class_method :_serializer_instance_methods
96
-
97
99
  attr_accessor :object, :root, :scope
98
100
 
99
101
  # `scope_name` is set as :current_user by default in the controller.
@@ -107,19 +109,72 @@ module ActiveModel
107
109
 
108
110
  scope_name = instance_options[:scope_name]
109
111
  if scope_name && !respond_to?(scope_name)
110
- self.class.class_eval do
111
- define_method scope_name, lambda { scope }
112
- end
112
+ define_singleton_method scope_name, lambda { scope }
113
113
  end
114
114
  end
115
115
 
116
+ def success?
117
+ true
118
+ end
119
+
120
+ # @return [Hash] containing the attributes and first level
121
+ # associations, similar to how ActiveModel::Serializers::JSON is used
122
+ # in ActiveRecord::Base.
123
+ #
124
+ # TODO: Move to here the Attributes adapter logic for
125
+ # +serializable_hash_for_single_resource(options)+
126
+ # and include <tt>ActiveModel::Serializers::JSON</tt>.
127
+ # So that the below is true:
128
+ # @param options [nil, Hash] The same valid options passed to `serializable_hash`
129
+ # (:only, :except, :methods, and :include).
130
+ #
131
+ # See
132
+ # https://github.com/rails/rails/blob/v5.0.0.beta2/activemodel/lib/active_model/serializers/json.rb#L17-L101
133
+ # https://github.com/rails/rails/blob/v5.0.0.beta2/activemodel/lib/active_model/serialization.rb#L85-L123
134
+ # https://github.com/rails/rails/blob/v5.0.0.beta2/activerecord/lib/active_record/serialization.rb#L11-L17
135
+ # https://github.com/rails/rails/blob/v5.0.0.beta2/activesupport/lib/active_support/core_ext/object/json.rb#L147-L162
136
+ #
137
+ # @example
138
+ # # The :only and :except options can be used to limit the attributes included, and work
139
+ # # similar to the attributes method.
140
+ # serializer.as_json(only: [:id, :name])
141
+ # serializer.as_json(except: [:id, :created_at, :age])
142
+ #
143
+ # # To include the result of some method calls on the model use :methods:
144
+ # serializer.as_json(methods: :permalink)
145
+ #
146
+ # # To include associations use :include:
147
+ # serializer.as_json(include: :posts)
148
+ # # Second level and higher order associations work as well:
149
+ # serializer.as_json(include: { posts: { include: { comments: { only: :body } }, only: :title } })
150
+ def serializable_hash(adapter_opts = nil)
151
+ adapter_opts ||= {}
152
+ adapter_opts = { include: '*', adapter: :attributes }.merge!(adapter_opts)
153
+ adapter = ActiveModelSerializers::Adapter.create(self, adapter_opts)
154
+ adapter.serializable_hash(adapter_opts)
155
+ end
156
+ alias to_hash serializable_hash
157
+ alias to_h serializable_hash
158
+
159
+ # @see #serializable_hash
160
+ # TODO: When moving attributes adapter logic here, @see #serializable_hash
161
+ # So that the below is true:
162
+ # @param options [nil, Hash] The same valid options passed to `as_json`
163
+ # (:root, :only, :except, :methods, and :include).
164
+ # The default for `root` is nil.
165
+ # The default value for include_root is false. You can change it to true if the given
166
+ # JSON string includes a single root node.
167
+ def as_json(adapter_opts = nil)
168
+ serializable_hash(adapter_opts)
169
+ end
170
+
116
171
  # Used by adapter as resource root.
117
172
  def json_key
118
- root || object.class.model_name.to_s.underscore
173
+ root || _type || object.class.model_name.to_s.underscore
119
174
  end
120
175
 
121
176
  def read_attribute_for_serialization(attr)
122
- if self.class._serializer_instance_method_defined?(attr)
177
+ if respond_to?(attr)
123
178
  send(attr)
124
179
  elsif self.class._fragmented
125
180
  self.class._fragmented.read_attribute_for_serialization(attr)
@@ -1,91 +1,24 @@
1
+ require 'active_model_serializers/adapter'
2
+ require 'active_model_serializers/deprecate'
3
+
1
4
  module ActiveModel
2
5
  class Serializer
6
+ # @deprecated Use ActiveModelSerializers::Adapter instead
3
7
  module Adapter
4
- UnknownAdapterError = Class.new(ArgumentError)
5
- ADAPTER_MAP = {}
6
- private_constant :ADAPTER_MAP if defined?(private_constant)
7
- require 'active_model/serializer/adapter/fragment_cache'
8
- require 'active_model/serializer/adapter/cached_serializer'
9
-
10
- class << self # All methods are class functions
11
- def new(*args)
12
- fail ArgumentError, 'Adapters inherit from Adapter::Base.' \
13
- "Adapter.new called with args: '#{args.inspect}', from" \
14
- "'caller[0]'."
15
- end
16
-
17
- def create(resource, options = {})
18
- override = options.delete(:adapter)
19
- klass = override ? adapter_class(override) : ActiveModel::Serializer.adapter
20
- klass.new(resource, options)
21
- end
22
-
23
- # @see ActiveModel::Serializer::Adapter.lookup
24
- def adapter_class(adapter)
25
- ActiveModel::Serializer::Adapter.lookup(adapter)
26
- end
27
-
28
- # @return Hash<adapter_name, adapter_class>
29
- def adapter_map
30
- ADAPTER_MAP
31
- end
8
+ class << self
9
+ extend ActiveModelSerializers::Deprecate
32
10
 
33
- # @return [Array<Symbol>] list of adapter names
34
- def adapters
35
- adapter_map.keys.sort
11
+ DEPRECATED_METHODS = [:create, :adapter_class, :adapter_map, :adapters, :register, :lookup].freeze
12
+ DEPRECATED_METHODS.each do |method|
13
+ delegate_and_deprecate method, ActiveModelSerializers::Adapter
36
14
  end
37
-
38
- # Adds an adapter 'klass' with 'name' to the 'adapter_map'
39
- # Names are stringified and underscored
40
- # @param name [Symbol, String, Class] name of the registered adapter
41
- # @param klass [Class] adapter class itself, optional if name is the class
42
- # @example
43
- # AMS::Adapter.register(:my_adapter, MyAdapter)
44
- # @note The registered name strips out 'ActiveModel::Serializer::Adapter::'
45
- # so that registering 'ActiveModel::Serializer::Adapter::Json' and
46
- # 'Json' will both register as 'json'.
47
- def register(name, klass = name)
48
- name = name.to_s.gsub(/\AActiveModel::Serializer::Adapter::/, ''.freeze)
49
- adapter_map.update(name.underscore => klass)
50
- self
51
- end
52
-
53
- # @param adapter [String, Symbol, Class] name to fetch adapter by
54
- # @return [ActiveModel::Serializer::Adapter] subclass of Adapter
55
- # @raise [UnknownAdapterError]
56
- def lookup(adapter)
57
- # 1. return if is a class
58
- return adapter if adapter.is_a?(Class)
59
- adapter_name = adapter.to_s.underscore
60
- # 2. return if registered
61
- adapter_map.fetch(adapter_name) do
62
- # 3. try to find adapter class from environment
63
- adapter_class = find_by_name(adapter_name)
64
- register(adapter_name, adapter_class)
65
- adapter_class
66
- end
67
- rescue NameError, ArgumentError => e
68
- failure_message =
69
- "NameError: #{e.message}. Unknown adapter: #{adapter.inspect}. Valid adapters are: #{adapters}"
70
- raise UnknownAdapterError, failure_message, e.backtrace
71
- end
72
-
73
- # @api private
74
- def find_by_name(adapter_name)
75
- adapter_name = adapter_name.to_s.classify.tr('API', 'Api')
76
- "ActiveModel::Serializer::Adapter::#{adapter_name}".safe_constantize ||
77
- "ActiveModel::Serializer::Adapter::#{adapter_name.pluralize}".safe_constantize or # rubocop:disable Style/AndOr
78
- fail UnknownAdapterError
79
- end
80
- private :find_by_name
81
15
  end
82
-
83
- # Gotta be at the bottom to use the code above it :(
84
- require 'active_model/serializer/adapter/base'
85
- require 'active_model/serializer/adapter/null'
86
- require 'active_model/serializer/adapter/attributes'
87
- require 'active_model/serializer/adapter/json'
88
- require 'active_model/serializer/adapter/json_api'
89
16
  end
90
17
  end
91
18
  end
19
+
20
+ require 'active_model/serializer/adapter/base'
21
+ require 'active_model/serializer/adapter/null'
22
+ require 'active_model/serializer/adapter/attributes'
23
+ require 'active_model/serializer/adapter/json'
24
+ require 'active_model/serializer/adapter/json_api'
@@ -1,64 +1,13 @@
1
1
  module ActiveModel
2
2
  class Serializer
3
3
  module Adapter
4
- class Attributes < Base
4
+ class Attributes < DelegateClass(ActiveModelSerializers::Adapter::Attributes)
5
5
  def initialize(serializer, options = {})
6
- super
7
- @include_tree = IncludeTree.from_include_args(options[:include] || '*')
6
+ super(ActiveModelSerializers::Adapter::Attributes.new(serializer, options))
8
7
  end
9
-
10
- def serializable_hash(options = nil)
11
- options ||= {}
12
-
13
- if serializer.respond_to?(:each)
14
- serializable_hash_for_collection(options)
15
- else
16
- serializable_hash_for_single_resource(options)
17
- end
18
- end
19
-
20
- def fragment_cache(cached_hash, non_cached_hash)
21
- Json::FragmentCache.new.fragment_cache(cached_hash, non_cached_hash)
22
- end
23
-
24
- private
25
-
26
- def serializable_hash_for_collection(options)
27
- serializer.map { |s| Attributes.new(s, instance_options).serializable_hash(options) }
28
- end
29
-
30
- def serializable_hash_for_single_resource(options)
31
- resource = resource_object_for(options)
32
- relationships = resource_relationships(options)
33
- resource.merge!(relationships)
34
- end
35
-
36
- def resource_relationships(options)
37
- relationships = {}
38
- serializer.associations(@include_tree).each do |association|
39
- relationships[association.key] = relationship_value_for(association, options)
40
- end
41
-
42
- relationships
43
- end
44
-
45
- def relationship_value_for(association, options)
46
- return association.options[:virtual_value] if association.options[:virtual_value]
47
- return unless association.serializer && association.serializer.object
48
-
49
- opts = instance_options.merge(include: @include_tree[association.key])
50
- Attributes.new(association.serializer, opts).serializable_hash(options)
51
- end
52
-
53
- # no-op: Attributes adapter does not include meta data, because it does not support root.
54
- def include_meta(json)
55
- json
56
- end
57
-
58
- def resource_object_for(options)
59
- cache_check(serializer) do
60
- serializer.attributes(options[:fields])
61
- end
8
+ class << self
9
+ extend ActiveModelSerializers::Deprecate
10
+ deprecate :new, 'ActiveModelSerializers::Adapter::Json.'
62
11
  end
63
12
  end
64
13
  end
@@ -1,56 +1,14 @@
1
1
  module ActiveModel
2
2
  class Serializer
3
3
  module Adapter
4
- class Base
5
- # Automatically register adapters when subclassing
6
- def self.inherited(subclass)
7
- ActiveModel::Serializer::Adapter.register(subclass)
4
+ class Base < DelegateClass(ActiveModelSerializers::Adapter::Base)
5
+ class << self
6
+ extend ActiveModelSerializers::Deprecate
7
+ deprecate :inherited, 'ActiveModelSerializers::Adapter::Base.'
8
8
  end
9
9
 
10
- attr_reader :serializer, :instance_options
11
-
12
10
  def initialize(serializer, options = {})
13
- @serializer = serializer
14
- @instance_options = options
15
- end
16
-
17
- def serializable_hash(_options = nil)
18
- fail NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.'
19
- end
20
-
21
- def as_json(options = nil)
22
- hash = serializable_hash(options)
23
- include_meta(hash)
24
- hash
25
- end
26
-
27
- def fragment_cache(*_args)
28
- fail NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.'
29
- end
30
-
31
- def cache_check(serializer)
32
- CachedSerializer.new(serializer).cache_check(self) do
33
- yield
34
- end
35
- end
36
-
37
- private
38
-
39
- def meta
40
- instance_options.fetch(:meta, nil)
41
- end
42
-
43
- def meta_key
44
- instance_options.fetch(:meta_key, 'meta'.freeze)
45
- end
46
-
47
- def root
48
- serializer.json_key.to_sym if serializer.json_key
49
- end
50
-
51
- def include_meta(json)
52
- json[meta_key] = meta if meta
53
- json
11
+ super(ActiveModelSerializers::Adapter::Base.new(serializer, options))
54
12
  end
55
13
  end
56
14
  end
@@ -1,19 +1,13 @@
1
1
  module ActiveModel
2
2
  class Serializer
3
3
  module Adapter
4
- class Json < Base
5
- extend ActiveSupport::Autoload
6
- autoload :FragmentCache
7
-
8
- def serializable_hash(options = nil)
9
- options ||= {}
10
- { root => Attributes.new(serializer, instance_options).serializable_hash(options) }
4
+ class Json < DelegateClass(ActiveModelSerializers::Adapter::Json)
5
+ def initialize(serializer, options = {})
6
+ super(ActiveModelSerializers::Adapter::Json.new(serializer, options))
11
7
  end
12
-
13
- private
14
-
15
- def fragment_cache(cached_hash, non_cached_hash)
16
- ActiveModel::Serializer::Adapter::Json::FragmentCache.new.fragment_cache(cached_hash, non_cached_hash)
8
+ class << self
9
+ extend ActiveModelSerializers::Deprecate
10
+ deprecate :new, 'ActiveModelSerializers::Adapter::Json.new'
17
11
  end
18
12
  end
19
13
  end
@@ -1,221 +1,13 @@
1
1
  module ActiveModel
2
2
  class Serializer
3
3
  module Adapter
4
- class JsonApi < Base
5
- extend ActiveSupport::Autoload
6
- autoload :PaginationLinks
7
- autoload :FragmentCache
8
- autoload :Link
9
- autoload :Deserialization
10
-
11
- # TODO: if we like this abstraction and other API objects to it,
12
- # then extract to its own file and require it.
13
- module ApiObjects
14
- module JsonApi
15
- ActiveModelSerializers.config.jsonapi_version = '1.0'
16
- ActiveModelSerializers.config.jsonapi_toplevel_meta = {}
17
- # Make JSON API top-level jsonapi member opt-in
18
- # ref: http://jsonapi.org/format/#document-top-level
19
- ActiveModelSerializers.config.jsonapi_include_toplevel_object = false
20
-
21
- module_function
22
-
23
- def add!(hash)
24
- hash.merge!(object) if include_object?
25
- end
26
-
27
- def include_object?
28
- ActiveModelSerializers.config.jsonapi_include_toplevel_object
29
- end
30
-
31
- # TODO: see if we can cache this
32
- def object
33
- object = {
34
- jsonapi: {
35
- version: ActiveModelSerializers.config.jsonapi_version,
36
- meta: ActiveModelSerializers.config.jsonapi_toplevel_meta
37
- }
38
- }
39
- object[:jsonapi].reject! { |_, v| v.blank? }
40
-
41
- object
42
- end
43
- end
44
- end
45
-
4
+ class JsonApi < DelegateClass(ActiveModelSerializers::Adapter::JsonApi)
46
5
  def initialize(serializer, options = {})
47
- super
48
- @include_tree = IncludeTree.from_include_args(options[:include])
49
- @fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
50
- end
51
-
52
- def serializable_hash(options = nil)
53
- options ||= {}
54
-
55
- hash =
56
- if serializer.respond_to?(:each)
57
- serializable_hash_for_collection(options)
58
- else
59
- serializable_hash_for_single_resource
60
- end
61
-
62
- ApiObjects::JsonApi.add!(hash)
63
-
64
- if instance_options[:links]
65
- hash[:links] ||= {}
66
- hash[:links].update(instance_options[:links])
67
- end
68
-
69
- hash
70
- end
71
-
72
- def fragment_cache(cached_hash, non_cached_hash)
73
- root = false if instance_options.include?(:include)
74
- ActiveModel::Serializer::Adapter::JsonApi::FragmentCache.new.fragment_cache(root, cached_hash, non_cached_hash)
75
- end
76
-
77
- protected
78
-
79
- attr_reader :fieldset
80
-
81
- private
82
-
83
- def serializable_hash_for_collection(options)
84
- hash = { data: [] }
85
- included = []
86
- serializer.each do |s|
87
- result = self.class.new(s, instance_options.merge(fieldset: fieldset)).serializable_hash(options)
88
- hash[:data] << result[:data]
89
- next unless result[:included]
90
-
91
- included |= result[:included]
92
- end
93
-
94
- included.delete_if { |resource| hash[:data].include?(resource) }
95
- hash[:included] = included if included.any?
96
-
97
- if serializer.paginated?
98
- hash[:links] ||= {}
99
- hash[:links].update(pagination_links_for(serializer, options))
100
- end
101
-
102
- hash
103
- end
104
-
105
- def serializable_hash_for_single_resource
106
- primary_data = resource_object_for(serializer)
107
-
108
- hash = { data: primary_data }
109
-
110
- included = included_resources(@include_tree, [primary_data])
111
- hash[:included] = included if included.any?
112
-
113
- hash
114
- end
115
-
116
- def resource_identifier_type_for(serializer)
117
- return serializer._type if serializer._type
118
- if ActiveModelSerializers.config.jsonapi_resource_type == :singular
119
- serializer.object.class.model_name.singular
120
- else
121
- serializer.object.class.model_name.plural
122
- end
123
- end
124
-
125
- def resource_identifier_id_for(serializer)
126
- if serializer.respond_to?(:id)
127
- serializer.id
128
- else
129
- serializer.object.id
130
- end
131
- end
132
-
133
- def resource_identifier_for(serializer)
134
- type = resource_identifier_type_for(serializer)
135
- id = resource_identifier_id_for(serializer)
136
-
137
- { id: id.to_s, type: type }
138
- end
139
-
140
- def attributes_for(serializer, fields)
141
- serializer.attributes(fields).except(:id)
142
- end
143
-
144
- def resource_object_for(serializer)
145
- resource_object = cache_check(serializer) do
146
- resource_object = resource_identifier_for(serializer)
147
-
148
- requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
149
- attributes = attributes_for(serializer, requested_fields)
150
- resource_object[:attributes] = attributes if attributes.any?
151
- resource_object
152
- end
153
-
154
- relationships = relationships_for(serializer)
155
- resource_object[:relationships] = relationships if relationships.any?
156
-
157
- links = links_for(serializer)
158
- resource_object[:links] = links if links.any?
159
-
160
- resource_object
161
- end
162
-
163
- def relationship_value_for(serializer, options = {})
164
- if serializer.respond_to?(:each)
165
- serializer.map { |s| resource_identifier_for(s) }
166
- else
167
- if options[:virtual_value]
168
- options[:virtual_value]
169
- elsif serializer && serializer.object
170
- resource_identifier_for(serializer)
171
- end
172
- end
173
- end
174
-
175
- def relationships_for(serializer)
176
- resource_type = resource_identifier_type_for(serializer)
177
- requested_associations = fieldset.fields_for(resource_type) || '*'
178
- include_tree = IncludeTree.from_include_args(requested_associations)
179
- serializer.associations(include_tree).each_with_object({}) do |association, hash|
180
- hash[association.key] = { data: relationship_value_for(association.serializer, association.options) }
181
- end
182
- end
183
-
184
- def included_resources(include_tree, primary_data)
185
- included = []
186
-
187
- serializer.associations(include_tree).each do |association|
188
- add_included_resources_for(association.serializer, include_tree[association.key], primary_data, included)
189
- end
190
-
191
- included
192
- end
193
-
194
- def add_included_resources_for(serializer, include_tree, primary_data, included)
195
- if serializer.respond_to?(:each)
196
- serializer.each { |s| add_included_resources_for(s, include_tree, primary_data, included) }
197
- else
198
- return unless serializer && serializer.object
199
-
200
- resource_object = resource_object_for(serializer)
201
-
202
- return if included.include?(resource_object) || primary_data.include?(resource_object)
203
- included.push(resource_object)
204
-
205
- serializer.associations(include_tree).each do |association|
206
- add_included_resources_for(association.serializer, include_tree[association.key], primary_data, included)
207
- end
208
- end
209
- end
210
-
211
- def links_for(serializer)
212
- serializer._links.each_with_object({}) do |(name, value), hash|
213
- hash[name] = Link.new(serializer, value).as_json
214
- end
6
+ super(ActiveModelSerializers::Adapter::JsonApi.new(serializer, options))
215
7
  end
216
-
217
- def pagination_links_for(serializer, options)
218
- JsonApi::PaginationLinks.new(serializer.object, options[:serialization_context]).serializable_hash(options)
8
+ class << self
9
+ extend ActiveModelSerializers::Deprecate
10
+ deprecate :new, 'ActiveModelSerializers::Adapter::JsonApi.new'
219
11
  end
220
12
  end
221
13
  end