active_model_serializers 0.8.3 → 0.10.8

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 (235) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE.md +29 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  4. data/.gitignore +17 -0
  5. data/.rubocop.yml +105 -0
  6. data/.simplecov +110 -0
  7. data/.travis.yml +50 -24
  8. data/CHANGELOG.md +650 -6
  9. data/CODE_OF_CONDUCT.md +74 -0
  10. data/CONTRIBUTING.md +105 -0
  11. data/Gemfile +69 -1
  12. data/{MIT-LICENSE.txt → MIT-LICENSE} +3 -2
  13. data/README.md +195 -545
  14. data/Rakefile +64 -8
  15. data/active_model_serializers.gemspec +62 -23
  16. data/appveyor.yml +28 -0
  17. data/bin/bench +171 -0
  18. data/bin/bench_regression +316 -0
  19. data/bin/rubocop +38 -0
  20. data/bin/serve_benchmark +39 -0
  21. data/docs/README.md +41 -0
  22. data/docs/STYLE.md +58 -0
  23. data/docs/general/adapters.md +269 -0
  24. data/docs/general/caching.md +58 -0
  25. data/docs/general/configuration_options.md +185 -0
  26. data/docs/general/deserialization.md +100 -0
  27. data/docs/general/fields.md +31 -0
  28. data/docs/general/getting_started.md +133 -0
  29. data/docs/general/instrumentation.md +40 -0
  30. data/docs/general/key_transforms.md +40 -0
  31. data/docs/general/logging.md +21 -0
  32. data/docs/general/rendering.md +293 -0
  33. data/docs/general/serializers.md +495 -0
  34. data/docs/how-open-source-maintained.jpg +0 -0
  35. data/docs/howto/add_pagination_links.md +138 -0
  36. data/docs/howto/add_relationship_links.md +140 -0
  37. data/docs/howto/add_root_key.md +62 -0
  38. data/docs/howto/grape_integration.md +42 -0
  39. data/docs/howto/outside_controller_use.md +66 -0
  40. data/docs/howto/passing_arbitrary_options.md +27 -0
  41. data/docs/howto/serialize_poro.md +73 -0
  42. data/docs/howto/test.md +154 -0
  43. data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
  44. data/docs/integrations/ember-and-json-api.md +147 -0
  45. data/docs/integrations/grape.md +19 -0
  46. data/docs/jsonapi/errors.md +56 -0
  47. data/docs/jsonapi/schema/schema.json +366 -0
  48. data/docs/jsonapi/schema.md +151 -0
  49. data/docs/rfcs/0000-namespace.md +106 -0
  50. data/docs/rfcs/template.md +15 -0
  51. data/lib/action_controller/serialization.rb +43 -38
  52. data/lib/active_model/serializable_resource.rb +11 -0
  53. data/lib/active_model/serializer/adapter/attributes.rb +15 -0
  54. data/lib/active_model/serializer/adapter/base.rb +18 -0
  55. data/lib/active_model/serializer/adapter/json.rb +15 -0
  56. data/lib/active_model/serializer/adapter/json_api.rb +15 -0
  57. data/lib/active_model/serializer/adapter/null.rb +15 -0
  58. data/lib/active_model/serializer/adapter.rb +24 -0
  59. data/lib/active_model/serializer/array_serializer.rb +12 -0
  60. data/lib/active_model/serializer/association.rb +71 -0
  61. data/lib/active_model/serializer/attribute.rb +25 -0
  62. data/lib/active_model/serializer/belongs_to_reflection.rb +11 -0
  63. data/lib/active_model/serializer/collection_serializer.rb +88 -0
  64. data/lib/active_model/serializer/concerns/caching.rb +300 -0
  65. data/lib/active_model/serializer/error_serializer.rb +14 -0
  66. data/lib/active_model/serializer/errors_serializer.rb +32 -0
  67. data/lib/active_model/serializer/field.rb +90 -0
  68. data/lib/active_model/serializer/fieldset.rb +31 -0
  69. data/lib/active_model/serializer/has_many_reflection.rb +10 -0
  70. data/lib/active_model/serializer/has_one_reflection.rb +7 -0
  71. data/lib/active_model/serializer/lazy_association.rb +96 -0
  72. data/lib/active_model/serializer/link.rb +21 -0
  73. data/lib/active_model/serializer/lint.rb +150 -0
  74. data/lib/active_model/serializer/null.rb +17 -0
  75. data/lib/active_model/serializer/reflection.rb +210 -0
  76. data/lib/active_model/{serializers → serializer}/version.rb +1 -1
  77. data/lib/active_model/serializer.rb +343 -442
  78. data/lib/active_model_serializers/adapter/attributes.rb +13 -0
  79. data/lib/active_model_serializers/adapter/base.rb +83 -0
  80. data/lib/active_model_serializers/adapter/json.rb +21 -0
  81. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +213 -0
  82. data/lib/active_model_serializers/adapter/json_api/error.rb +96 -0
  83. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +49 -0
  84. data/lib/active_model_serializers/adapter/json_api/link.rb +83 -0
  85. data/lib/active_model_serializers/adapter/json_api/meta.rb +37 -0
  86. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +88 -0
  87. data/lib/active_model_serializers/adapter/json_api/relationship.rb +104 -0
  88. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +66 -0
  89. data/lib/active_model_serializers/adapter/json_api.rb +533 -0
  90. data/lib/active_model_serializers/adapter/null.rb +9 -0
  91. data/lib/active_model_serializers/adapter.rb +98 -0
  92. data/lib/active_model_serializers/callbacks.rb +55 -0
  93. data/lib/active_model_serializers/deprecate.rb +54 -0
  94. data/lib/active_model_serializers/deserialization.rb +15 -0
  95. data/lib/active_model_serializers/json_pointer.rb +14 -0
  96. data/lib/active_model_serializers/logging.rb +122 -0
  97. data/lib/active_model_serializers/lookup_chain.rb +80 -0
  98. data/lib/active_model_serializers/model.rb +130 -0
  99. data/lib/active_model_serializers/railtie.rb +50 -0
  100. data/lib/active_model_serializers/register_jsonapi_renderer.rb +78 -0
  101. data/lib/active_model_serializers/serializable_resource.rb +82 -0
  102. data/lib/active_model_serializers/serialization_context.rb +39 -0
  103. data/lib/active_model_serializers/test/schema.rb +138 -0
  104. data/lib/active_model_serializers/test/serializer.rb +125 -0
  105. data/lib/active_model_serializers/test.rb +7 -0
  106. data/lib/active_model_serializers.rb +47 -81
  107. data/lib/generators/rails/USAGE +6 -0
  108. data/lib/generators/rails/resource_override.rb +10 -0
  109. data/lib/generators/rails/serializer_generator.rb +36 -0
  110. data/lib/generators/rails/templates/serializer.rb.erb +8 -0
  111. data/lib/grape/active_model_serializers.rb +16 -0
  112. data/lib/grape/formatters/active_model_serializers.rb +32 -0
  113. data/lib/grape/helpers/active_model_serializers.rb +17 -0
  114. data/lib/tasks/rubocop.rake +53 -0
  115. data/test/action_controller/adapter_selector_test.rb +62 -0
  116. data/test/action_controller/explicit_serializer_test.rb +135 -0
  117. data/test/action_controller/json/include_test.rb +246 -0
  118. data/test/action_controller/json_api/deserialization_test.rb +112 -0
  119. data/test/action_controller/json_api/errors_test.rb +40 -0
  120. data/test/action_controller/json_api/fields_test.rb +66 -0
  121. data/test/action_controller/json_api/linked_test.rb +202 -0
  122. data/test/action_controller/json_api/pagination_test.rb +124 -0
  123. data/test/action_controller/json_api/transform_test.rb +189 -0
  124. data/test/action_controller/lookup_proc_test.rb +49 -0
  125. data/test/action_controller/namespace_lookup_test.rb +232 -0
  126. data/test/action_controller/serialization_scope_name_test.rb +235 -0
  127. data/test/action_controller/serialization_test.rb +478 -0
  128. data/test/active_model_serializers/adapter_for_test.rb +208 -0
  129. data/test/active_model_serializers/json_pointer_test.rb +22 -0
  130. data/test/active_model_serializers/logging_test.rb +77 -0
  131. data/test/active_model_serializers/model_test.rb +142 -0
  132. data/test/active_model_serializers/railtie_test_isolated.rb +68 -0
  133. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +161 -0
  134. data/test/active_model_serializers/serialization_context_test_isolated.rb +71 -0
  135. data/test/active_model_serializers/test/schema_test.rb +131 -0
  136. data/test/active_model_serializers/test/serializer_test.rb +62 -0
  137. data/test/active_record_test.rb +9 -0
  138. data/test/adapter/attributes_test.rb +40 -0
  139. data/test/adapter/deprecation_test.rb +100 -0
  140. data/test/adapter/json/belongs_to_test.rb +45 -0
  141. data/test/adapter/json/collection_test.rb +104 -0
  142. data/test/adapter/json/has_many_test.rb +53 -0
  143. data/test/adapter/json/transform_test.rb +93 -0
  144. data/test/adapter/json_api/belongs_to_test.rb +155 -0
  145. data/test/adapter/json_api/collection_test.rb +96 -0
  146. data/test/adapter/json_api/errors_test.rb +76 -0
  147. data/test/adapter/json_api/fields_test.rb +96 -0
  148. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +96 -0
  149. data/test/adapter/json_api/has_many_test.rb +173 -0
  150. data/test/adapter/json_api/has_one_test.rb +80 -0
  151. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +213 -0
  152. data/test/adapter/json_api/json_api_test.rb +33 -0
  153. data/test/adapter/json_api/linked_test.rb +413 -0
  154. data/test/adapter/json_api/links_test.rb +110 -0
  155. data/test/adapter/json_api/pagination_links_test.rb +206 -0
  156. data/test/adapter/json_api/parse_test.rb +137 -0
  157. data/test/adapter/json_api/relationship_test.rb +397 -0
  158. data/test/adapter/json_api/resource_meta_test.rb +100 -0
  159. data/test/adapter/json_api/toplevel_jsonapi_test.rb +82 -0
  160. data/test/adapter/json_api/transform_test.rb +512 -0
  161. data/test/adapter/json_api/type_test.rb +193 -0
  162. data/test/adapter/json_test.rb +46 -0
  163. data/test/adapter/null_test.rb +22 -0
  164. data/test/adapter/polymorphic_test.rb +218 -0
  165. data/test/adapter_test.rb +67 -0
  166. data/test/array_serializer_test.rb +20 -73
  167. data/test/benchmark/app.rb +65 -0
  168. data/test/benchmark/benchmarking_support.rb +67 -0
  169. data/test/benchmark/bm_active_record.rb +81 -0
  170. data/test/benchmark/bm_adapter.rb +38 -0
  171. data/test/benchmark/bm_caching.rb +119 -0
  172. data/test/benchmark/bm_lookup_chain.rb +83 -0
  173. data/test/benchmark/bm_transform.rb +45 -0
  174. data/test/benchmark/config.ru +3 -0
  175. data/test/benchmark/controllers.rb +83 -0
  176. data/test/benchmark/fixtures.rb +219 -0
  177. data/test/cache_test.rb +651 -0
  178. data/test/collection_serializer_test.rb +127 -0
  179. data/test/fixtures/active_record.rb +113 -0
  180. data/test/fixtures/poro.rb +225 -0
  181. data/test/generators/scaffold_controller_generator_test.rb +24 -0
  182. data/test/generators/serializer_generator_test.rb +75 -0
  183. data/test/grape_test.rb +196 -0
  184. data/test/lint_test.rb +49 -0
  185. data/test/logger_test.rb +20 -0
  186. data/test/poro_test.rb +9 -0
  187. data/test/serializable_resource_test.rb +79 -0
  188. data/test/serializers/association_macros_test.rb +37 -0
  189. data/test/serializers/associations_test.rb +518 -0
  190. data/test/serializers/attribute_test.rb +153 -0
  191. data/test/serializers/attributes_test.rb +52 -0
  192. data/test/serializers/caching_configuration_test_isolated.rb +170 -0
  193. data/test/serializers/configuration_test.rb +32 -0
  194. data/test/serializers/fieldset_test.rb +14 -0
  195. data/test/serializers/meta_test.rb +202 -0
  196. data/test/serializers/options_test.rb +32 -0
  197. data/test/serializers/read_attribute_for_serialization_test.rb +79 -0
  198. data/test/serializers/reflection_test.rb +479 -0
  199. data/test/serializers/root_test.rb +21 -0
  200. data/test/serializers/serialization_test.rb +55 -0
  201. data/test/serializers/serializer_for_test.rb +136 -0
  202. data/test/serializers/serializer_for_with_namespace_test.rb +88 -0
  203. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  204. data/test/support/isolated_unit.rb +84 -0
  205. data/test/support/rails5_shims.rb +53 -0
  206. data/test/support/rails_app.rb +38 -0
  207. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  208. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
  209. data/test/support/schemas/custom/show.json +7 -0
  210. data/test/support/schemas/hyper_schema.json +93 -0
  211. data/test/support/schemas/render_using_json_api.json +43 -0
  212. data/test/support/schemas/simple_json_pointers.json +10 -0
  213. data/test/support/serialization_testing.rb +79 -0
  214. data/test/test_helper.rb +59 -21
  215. metadata +529 -43
  216. data/DESIGN.textile +0 -586
  217. data/Gemfile.edge +0 -9
  218. data/bench/perf.rb +0 -43
  219. data/cruft.md +0 -19
  220. data/lib/active_model/array_serializer.rb +0 -104
  221. data/lib/active_model/serializer/associations.rb +0 -233
  222. data/lib/active_record/serializer_override.rb +0 -16
  223. data/lib/generators/resource_override.rb +0 -13
  224. data/lib/generators/serializer/USAGE +0 -9
  225. data/lib/generators/serializer/serializer_generator.rb +0 -42
  226. data/lib/generators/serializer/templates/serializer.rb +0 -19
  227. data/test/association_test.rb +0 -592
  228. data/test/caching_test.rb +0 -96
  229. data/test/generators_test.rb +0 -85
  230. data/test/no_serialization_scope_test.rb +0 -34
  231. data/test/serialization_scope_name_test.rb +0 -67
  232. data/test/serialization_test.rb +0 -392
  233. data/test/serializer_support_test.rb +0 -51
  234. data/test/serializer_test.rb +0 -1465
  235. data/test/test_fakes.rb +0 -217
@@ -1,60 +1,65 @@
1
+ require 'active_support/core_ext/class/attribute'
2
+ require 'active_model_serializers/serialization_context'
3
+
1
4
  module ActionController
2
- # Action Controller Serialization
3
- #
4
- # Overrides render :json to check if the given object implements +active_model_serializer+
5
- # as a method. If so, use the returned serializer instead of calling +to_json+ on the object.
6
- #
7
- # This module also provides a serialization_scope method that allows you to configure the
8
- # +serialization_scope+ of the serializer. Most apps will likely set the +serialization_scope+
9
- # to the current user:
10
- #
11
- # class ApplicationController < ActionController::Base
12
- # serialization_scope :current_user
13
- # end
14
- #
15
- # If you need more complex scope rules, you can simply override the serialization_scope:
16
- #
17
- # class ApplicationController < ActionController::Base
18
- # private
19
- #
20
- # def serialization_scope
21
- # current_user
22
- # end
23
- # end
24
- #
25
5
  module Serialization
26
6
  extend ActiveSupport::Concern
27
7
 
28
8
  include ActionController::Renderers
29
9
 
10
+ module ClassMethods
11
+ def serialization_scope(scope)
12
+ self._serialization_scope = scope
13
+ end
14
+ end
15
+
30
16
  included do
31
17
  class_attribute :_serialization_scope
32
18
  self._serialization_scope = :current_user
19
+
20
+ attr_writer :namespace_for_serializer
21
+ end
22
+
23
+ def namespace_for_serializer
24
+ @namespace_for_serializer ||= self.class.parent unless self.class.parent == Object
33
25
  end
34
26
 
35
27
  def serialization_scope
36
- send(_serialization_scope) if _serialization_scope &&
37
- respond_to?(_serialization_scope, true)
28
+ return unless _serialization_scope && respond_to?(_serialization_scope, true)
29
+
30
+ send(_serialization_scope)
38
31
  end
39
32
 
40
- def default_serializer_options
33
+ def get_serializer(resource, options = {})
34
+ unless use_adapter?
35
+ warn 'ActionController::Serialization#use_adapter? has been removed. '\
36
+ "Please pass 'adapter: false' or see ActiveSupport::SerializableResource.new"
37
+ options[:adapter] = false
38
+ end
39
+
40
+ options.fetch(:namespace) { options[:namespace] = namespace_for_serializer }
41
+
42
+ serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)
43
+ serializable_resource.serialization_scope ||= options.fetch(:scope) { serialization_scope }
44
+ serializable_resource.serialization_scope_name = options.fetch(:scope_name) { _serialization_scope }
45
+ # For compatibility with the JSON renderer: `json.to_json(options) if json.is_a?(String)`.
46
+ # Otherwise, since `serializable_resource` is not a string, the renderer would call
47
+ # `to_json` on a String and given odd results, such as `"".to_json #=> '""'`
48
+ serializable_resource.adapter.is_a?(String) ? serializable_resource.adapter : serializable_resource
49
+ end
50
+
51
+ # Deprecated
52
+ def use_adapter?
53
+ true
41
54
  end
42
55
 
43
56
  [:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
44
57
  define_method renderer_method do |resource, options|
45
- json = ActiveModel::Serializer.build_json(self, resource, options)
46
-
47
- if json
48
- super(json, options)
49
- else
50
- super(resource, options)
58
+ options.fetch(:serialization_context) do
59
+ options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request, options)
51
60
  end
52
- end
53
- end
54
-
55
- module ClassMethods
56
- def serialization_scope(scope)
57
- self._serialization_scope = scope
61
+ serializable_resource = get_serializer(resource, options)
62
+ super(serializable_resource, options)
58
63
  end
59
64
  end
60
65
  end
@@ -0,0 +1,11 @@
1
+ require 'set'
2
+
3
+ module ActiveModel
4
+ class SerializableResource
5
+ class << self
6
+ extend ActiveModelSerializers::Deprecate
7
+
8
+ delegate_and_deprecate :new, ActiveModelSerializers::SerializableResource
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ module Adapter
4
+ class Attributes < DelegateClass(ActiveModelSerializers::Adapter::Attributes)
5
+ def initialize(serializer, options = {})
6
+ super(ActiveModelSerializers::Adapter::Attributes.new(serializer, options))
7
+ end
8
+ class << self
9
+ extend ActiveModelSerializers::Deprecate
10
+ deprecate :new, 'ActiveModelSerializers::Adapter::Json.'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ module Adapter
4
+ class Base < DelegateClass(ActiveModelSerializers::Adapter::Base)
5
+ class << self
6
+ extend ActiveModelSerializers::Deprecate
7
+ deprecate :inherited, 'ActiveModelSerializers::Adapter::Base.'
8
+ end
9
+
10
+ # :nocov:
11
+ def initialize(serializer, options = {})
12
+ super(ActiveModelSerializers::Adapter::Base.new(serializer, options))
13
+ end
14
+ # :nocov:
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ module Adapter
4
+ class Json < DelegateClass(ActiveModelSerializers::Adapter::Json)
5
+ def initialize(serializer, options = {})
6
+ super(ActiveModelSerializers::Adapter::Json.new(serializer, options))
7
+ end
8
+ class << self
9
+ extend ActiveModelSerializers::Deprecate
10
+ deprecate :new, 'ActiveModelSerializers::Adapter::Json.new'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ module Adapter
4
+ class JsonApi < DelegateClass(ActiveModelSerializers::Adapter::JsonApi)
5
+ def initialize(serializer, options = {})
6
+ super(ActiveModelSerializers::Adapter::JsonApi.new(serializer, options))
7
+ end
8
+ class << self
9
+ extend ActiveModelSerializers::Deprecate
10
+ deprecate :new, 'ActiveModelSerializers::Adapter::JsonApi.new'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ module Adapter
4
+ class Null < DelegateClass(ActiveModelSerializers::Adapter::Null)
5
+ def initialize(serializer, options = {})
6
+ super(ActiveModelSerializers::Adapter::Null.new(serializer, options))
7
+ end
8
+ class << self
9
+ extend ActiveModelSerializers::Deprecate
10
+ deprecate :new, 'ActiveModelSerializers::Adapter::Null.new'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ require 'active_model_serializers/adapter'
2
+ require 'active_model_serializers/deprecate'
3
+
4
+ module ActiveModel
5
+ class Serializer
6
+ # @deprecated Use ActiveModelSerializers::Adapter instead
7
+ module Adapter
8
+ class << self
9
+ extend ActiveModelSerializers::Deprecate
10
+
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
14
+ end
15
+ end
16
+ end
17
+ end
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'
@@ -0,0 +1,12 @@
1
+ require 'active_model/serializer/collection_serializer'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class ArraySerializer < CollectionSerializer
6
+ class << self
7
+ extend ActiveModelSerializers::Deprecate
8
+ deprecate :new, 'ActiveModel::Serializer::CollectionSerializer.'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,71 @@
1
+ require 'active_model/serializer/lazy_association'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ # This class holds all information about serializer's association.
6
+ #
7
+ # @api private
8
+ Association = Struct.new(:reflection, :association_options) do
9
+ attr_reader :lazy_association
10
+ delegate :object, :include_data?, :virtual_value, :collection?, to: :lazy_association
11
+
12
+ def initialize(*)
13
+ super
14
+ @lazy_association = LazyAssociation.new(reflection, association_options)
15
+ end
16
+
17
+ # @return [Symbol]
18
+ delegate :name, to: :reflection
19
+
20
+ # @return [Symbol]
21
+ def key
22
+ reflection_options.fetch(:key, name)
23
+ end
24
+
25
+ # @return [True,False]
26
+ def key?
27
+ reflection_options.key?(:key)
28
+ end
29
+
30
+ # @return [Hash]
31
+ def links
32
+ reflection_options.fetch(:links) || {}
33
+ end
34
+
35
+ # @return [Hash, nil]
36
+ # This gets mutated, so cannot use the cached reflection_options
37
+ def meta
38
+ reflection.options[:meta]
39
+ end
40
+
41
+ def belongs_to?
42
+ reflection.foreign_key_on == :self
43
+ end
44
+
45
+ def polymorphic?
46
+ true == reflection_options[:polymorphic]
47
+ end
48
+
49
+ # @api private
50
+ def serializable_hash(adapter_options, adapter_instance)
51
+ association_serializer = lazy_association.serializer
52
+ return virtual_value if virtual_value
53
+ association_object = association_serializer && association_serializer.object
54
+ return unless association_object
55
+
56
+ serialization = association_serializer.serializable_hash(adapter_options, {}, adapter_instance)
57
+
58
+ if polymorphic? && serialization
59
+ polymorphic_type = association_object.class.name.underscore
60
+ serialization = { type: polymorphic_type, polymorphic_type.to_sym => serialization }
61
+ end
62
+
63
+ serialization
64
+ end
65
+
66
+ private
67
+
68
+ delegate :reflection_options, to: :lazy_association
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,25 @@
1
+ require 'active_model/serializer/field'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ # Holds all the meta-data about an attribute as it was specified in the
6
+ # ActiveModel::Serializer class.
7
+ #
8
+ # @example
9
+ # class PostSerializer < ActiveModel::Serializer
10
+ # attribute :content
11
+ # attribute :name, key: :title
12
+ # attribute :email, key: :author_email, if: :user_logged_in?
13
+ # attribute :preview do
14
+ # truncate(object.content)
15
+ # end
16
+ #
17
+ # def user_logged_in?
18
+ # current_user.logged_in?
19
+ # end
20
+ # end
21
+ #
22
+ class Attribute < Field
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ # @api private
4
+ class BelongsToReflection < Reflection
5
+ # @api private
6
+ def foreign_key_on
7
+ :self
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,88 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ class CollectionSerializer
4
+ include Enumerable
5
+ delegate :each, to: :@serializers
6
+
7
+ attr_reader :object, :root
8
+
9
+ def initialize(resources, options = {})
10
+ @object = resources
11
+ @options = options
12
+ @root = options[:root]
13
+ @serializers = serializers_from_resources
14
+ end
15
+
16
+ def success?
17
+ true
18
+ end
19
+
20
+ # @api private
21
+ def serializable_hash(adapter_options, options, adapter_instance)
22
+ options[:include_directive] ||= ActiveModel::Serializer.include_directive_from_options(adapter_options)
23
+ options[:cached_attributes] ||= ActiveModel::Serializer.cache_read_multi(self, adapter_instance, options[:include_directive])
24
+ serializers.map do |serializer|
25
+ serializer.serializable_hash(adapter_options, options, adapter_instance)
26
+ end
27
+ end
28
+
29
+ # TODO: unify naming of root, json_key, and _type. Right now, a serializer's
30
+ # json_key comes from the root option or the object's model name, by default.
31
+ # But, if a dev defines a custom `json_key` method with an explicit value,
32
+ # we have no simple way to know that it is safe to call that instance method.
33
+ # (which is really a class property at this point, anyhow).
34
+ # rubocop:disable Metrics/CyclomaticComplexity
35
+ # Disabling cop since it's good to highlight the complexity of this method by
36
+ # including all the logic right here.
37
+ def json_key
38
+ return root if root
39
+ # 1. get from options[:serializer] for empty resource collection
40
+ key = object.empty? &&
41
+ (explicit_serializer_class = options[:serializer]) &&
42
+ explicit_serializer_class._type
43
+ # 2. get from first serializer instance in collection
44
+ key ||= (serializer = serializers.first) && serializer.json_key
45
+ # 3. get from collection name, if a named collection
46
+ key ||= object.respond_to?(:name) ? object.name && object.name.underscore : nil
47
+ # 4. key may be nil for empty collection and no serializer option
48
+ key &&= key.pluralize
49
+ # 5. fail if the key cannot be determined
50
+ key || fail(ArgumentError, 'Cannot infer root key from collection type. Please specify the root or each_serializer option, or render a JSON String')
51
+ end
52
+ # rubocop:enable Metrics/CyclomaticComplexity
53
+
54
+ def paginated?
55
+ ActiveModelSerializers.config.jsonapi_pagination_links_enabled &&
56
+ object.respond_to?(:current_page) &&
57
+ object.respond_to?(:total_pages) &&
58
+ object.respond_to?(:size)
59
+ end
60
+
61
+ protected
62
+
63
+ attr_reader :serializers, :options
64
+
65
+ private
66
+
67
+ def serializers_from_resources
68
+ serializer_context_class = options.fetch(:serializer_context_class, ActiveModel::Serializer)
69
+ object.map do |resource|
70
+ serializer_from_resource(resource, serializer_context_class, options)
71
+ end
72
+ end
73
+
74
+ def serializer_from_resource(resource, serializer_context_class, options)
75
+ serializer_class = options.fetch(:serializer) do
76
+ serializer_context_class.serializer_for(resource, namespace: options[:namespace])
77
+ end
78
+
79
+ if serializer_class.nil?
80
+ ActiveModelSerializers.logger.debug "No serializer found for resource: #{resource.inspect}"
81
+ throw :no_serializer
82
+ else
83
+ serializer_class.new(resource, options.except(:serializer))
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end