active_model_serializers 0.10.0 → 0.10.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (215) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +227 -2
  3. data/README.md +171 -33
  4. data/lib/action_controller/serialization.rb +23 -3
  5. data/lib/active_model/serializable_resource.rb +2 -0
  6. data/lib/active_model/serializer/adapter/attributes.rb +2 -0
  7. data/lib/active_model/serializer/adapter/base.rb +4 -0
  8. data/lib/active_model/serializer/adapter/json.rb +2 -0
  9. data/lib/active_model/serializer/adapter/json_api.rb +2 -0
  10. data/lib/active_model/serializer/adapter/null.rb +2 -0
  11. data/lib/active_model/serializer/adapter.rb +2 -0
  12. data/lib/active_model/serializer/array_serializer.rb +10 -5
  13. data/lib/active_model/serializer/association.rb +64 -10
  14. data/lib/active_model/serializer/attribute.rb +2 -0
  15. data/lib/active_model/serializer/belongs_to_reflection.rb +6 -3
  16. data/lib/active_model/serializer/collection_serializer.rb +39 -13
  17. data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +89 -117
  18. data/lib/active_model/serializer/error_serializer.rb +13 -7
  19. data/lib/active_model/serializer/errors_serializer.rb +27 -20
  20. data/lib/active_model/serializer/field.rb +2 -0
  21. data/lib/active_model/serializer/fieldset.rb +3 -1
  22. data/lib/active_model/serializer/has_many_reflection.rb +5 -3
  23. data/lib/active_model/serializer/has_one_reflection.rb +3 -4
  24. data/lib/active_model/serializer/lazy_association.rb +99 -0
  25. data/lib/active_model/serializer/link.rb +23 -0
  26. data/lib/active_model/serializer/lint.rb +136 -130
  27. data/lib/active_model/serializer/null.rb +2 -0
  28. data/lib/active_model/serializer/reflection.rb +130 -65
  29. data/lib/active_model/serializer/version.rb +3 -1
  30. data/lib/active_model/serializer.rb +319 -86
  31. data/lib/active_model_serializers/adapter/attributes.rb +17 -57
  32. data/lib/active_model_serializers/adapter/base.rb +41 -39
  33. data/lib/active_model_serializers/adapter/json.rb +2 -0
  34. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +4 -2
  35. data/lib/active_model_serializers/adapter/json_api/error.rb +2 -0
  36. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +2 -0
  37. data/lib/active_model_serializers/adapter/json_api/link.rb +3 -1
  38. data/lib/active_model_serializers/adapter/json_api/meta.rb +2 -0
  39. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +49 -21
  40. data/lib/active_model_serializers/adapter/json_api/relationship.rb +77 -23
  41. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +41 -10
  42. data/lib/active_model_serializers/adapter/json_api.rb +84 -65
  43. data/lib/active_model_serializers/adapter/null.rb +2 -0
  44. data/lib/active_model_serializers/adapter.rb +9 -1
  45. data/lib/active_model_serializers/callbacks.rb +2 -0
  46. data/lib/active_model_serializers/deprecate.rb +3 -2
  47. data/lib/active_model_serializers/deserialization.rb +4 -0
  48. data/lib/active_model_serializers/json_pointer.rb +2 -0
  49. data/lib/active_model_serializers/logging.rb +2 -0
  50. data/lib/active_model_serializers/lookup_chain.rb +82 -0
  51. data/lib/active_model_serializers/model/caching.rb +25 -0
  52. data/lib/active_model_serializers/model.rb +111 -28
  53. data/lib/active_model_serializers/railtie.rb +7 -1
  54. data/lib/active_model_serializers/register_jsonapi_renderer.rb +46 -31
  55. data/lib/active_model_serializers/serializable_resource.rb +10 -7
  56. data/lib/active_model_serializers/serialization_context.rb +12 -3
  57. data/lib/active_model_serializers/test/schema.rb +4 -2
  58. data/lib/active_model_serializers/test/serializer.rb +2 -0
  59. data/lib/active_model_serializers/test.rb +2 -0
  60. data/lib/active_model_serializers.rb +35 -10
  61. data/lib/generators/rails/resource_override.rb +3 -1
  62. data/lib/generators/rails/serializer_generator.rb +6 -4
  63. data/lib/grape/active_model_serializers.rb +9 -5
  64. data/lib/grape/formatters/active_model_serializers.rb +21 -2
  65. data/lib/grape/helpers/active_model_serializers.rb +3 -0
  66. data/lib/tasks/rubocop.rake +55 -0
  67. metadata +110 -276
  68. data/.github/ISSUE_TEMPLATE.md +0 -29
  69. data/.github/PULL_REQUEST_TEMPLATE.md +0 -15
  70. data/.gitignore +0 -35
  71. data/.rubocop.yml +0 -104
  72. data/.rubocop_todo.yml +0 -167
  73. data/.simplecov +0 -110
  74. data/.travis.yml +0 -43
  75. data/CONTRIBUTING.md +0 -105
  76. data/Gemfile +0 -53
  77. data/Rakefile +0 -103
  78. data/active_model_serializers.gemspec +0 -66
  79. data/appveyor.yml +0 -24
  80. data/bin/bench +0 -171
  81. data/bin/bench_regression +0 -316
  82. data/bin/serve_benchmark +0 -39
  83. data/docs/ARCHITECTURE.md +0 -126
  84. data/docs/README.md +0 -40
  85. data/docs/STYLE.md +0 -58
  86. data/docs/general/adapters.md +0 -245
  87. data/docs/general/caching.md +0 -52
  88. data/docs/general/configuration_options.md +0 -100
  89. data/docs/general/deserialization.md +0 -100
  90. data/docs/general/getting_started.md +0 -133
  91. data/docs/general/instrumentation.md +0 -40
  92. data/docs/general/key_transforms.md +0 -40
  93. data/docs/general/logging.md +0 -14
  94. data/docs/general/rendering.md +0 -255
  95. data/docs/general/serializers.md +0 -372
  96. data/docs/how-open-source-maintained.jpg +0 -0
  97. data/docs/howto/add_pagination_links.md +0 -139
  98. data/docs/howto/add_root_key.md +0 -51
  99. data/docs/howto/outside_controller_use.md +0 -58
  100. data/docs/howto/passing_arbitrary_options.md +0 -27
  101. data/docs/howto/serialize_poro.md +0 -32
  102. data/docs/howto/test.md +0 -152
  103. data/docs/integrations/ember-and-json-api.md +0 -112
  104. data/docs/integrations/grape.md +0 -19
  105. data/docs/jsonapi/errors.md +0 -56
  106. data/docs/jsonapi/schema/schema.json +0 -366
  107. data/docs/jsonapi/schema.md +0 -151
  108. data/docs/rfcs/0000-namespace.md +0 -106
  109. data/docs/rfcs/template.md +0 -15
  110. data/lib/active_model/serializer/associations.rb +0 -100
  111. data/lib/active_model/serializer/attributes.rb +0 -82
  112. data/lib/active_model/serializer/collection_reflection.rb +0 -7
  113. data/lib/active_model/serializer/configuration.rb +0 -35
  114. data/lib/active_model/serializer/include_tree.rb +0 -111
  115. data/lib/active_model/serializer/links.rb +0 -35
  116. data/lib/active_model/serializer/meta.rb +0 -29
  117. data/lib/active_model/serializer/singular_reflection.rb +0 -7
  118. data/lib/active_model/serializer/type.rb +0 -25
  119. data/lib/active_model_serializers/key_transform.rb +0 -70
  120. data/test/action_controller/adapter_selector_test.rb +0 -53
  121. data/test/action_controller/explicit_serializer_test.rb +0 -134
  122. data/test/action_controller/json/include_test.rb +0 -167
  123. data/test/action_controller/json_api/deserialization_test.rb +0 -112
  124. data/test/action_controller/json_api/errors_test.rb +0 -41
  125. data/test/action_controller/json_api/linked_test.rb +0 -197
  126. data/test/action_controller/json_api/pagination_test.rb +0 -116
  127. data/test/action_controller/json_api/transform_test.rb +0 -181
  128. data/test/action_controller/serialization_scope_name_test.rb +0 -229
  129. data/test/action_controller/serialization_test.rb +0 -469
  130. data/test/active_model_serializers/adapter_for_test.rb +0 -208
  131. data/test/active_model_serializers/json_pointer_test.rb +0 -20
  132. data/test/active_model_serializers/key_transform_test.rb +0 -263
  133. data/test/active_model_serializers/logging_test.rb +0 -77
  134. data/test/active_model_serializers/model_test.rb +0 -9
  135. data/test/active_model_serializers/railtie_test_isolated.rb +0 -63
  136. data/test/active_model_serializers/serialization_context_test_isolated.rb +0 -58
  137. data/test/active_model_serializers/test/schema_test.rb +0 -130
  138. data/test/active_model_serializers/test/serializer_test.rb +0 -62
  139. data/test/active_record_test.rb +0 -9
  140. data/test/adapter/deprecation_test.rb +0 -100
  141. data/test/adapter/json/belongs_to_test.rb +0 -45
  142. data/test/adapter/json/collection_test.rb +0 -90
  143. data/test/adapter/json/has_many_test.rb +0 -45
  144. data/test/adapter/json/transform_test.rb +0 -93
  145. data/test/adapter/json_api/belongs_to_test.rb +0 -155
  146. data/test/adapter/json_api/collection_test.rb +0 -95
  147. data/test/adapter/json_api/errors_test.rb +0 -78
  148. data/test/adapter/json_api/fields_test.rb +0 -87
  149. data/test/adapter/json_api/has_many_embed_ids_test.rb +0 -43
  150. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +0 -96
  151. data/test/adapter/json_api/has_many_test.rb +0 -144
  152. data/test/adapter/json_api/has_one_test.rb +0 -80
  153. data/test/adapter/json_api/json_api_test.rb +0 -35
  154. data/test/adapter/json_api/linked_test.rb +0 -392
  155. data/test/adapter/json_api/links_test.rb +0 -93
  156. data/test/adapter/json_api/pagination_links_test.rb +0 -166
  157. data/test/adapter/json_api/parse_test.rb +0 -137
  158. data/test/adapter/json_api/relationship_test.rb +0 -161
  159. data/test/adapter/json_api/relationships_test.rb +0 -199
  160. data/test/adapter/json_api/resource_identifier_test.rb +0 -85
  161. data/test/adapter/json_api/resource_meta_test.rb +0 -100
  162. data/test/adapter/json_api/toplevel_jsonapi_test.rb +0 -82
  163. data/test/adapter/json_api/transform_test.rb +0 -502
  164. data/test/adapter/json_api/type_test.rb +0 -61
  165. data/test/adapter/json_test.rb +0 -45
  166. data/test/adapter/null_test.rb +0 -23
  167. data/test/adapter/polymorphic_test.rb +0 -171
  168. data/test/adapter_test.rb +0 -67
  169. data/test/array_serializer_test.rb +0 -22
  170. data/test/benchmark/app.rb +0 -65
  171. data/test/benchmark/benchmarking_support.rb +0 -67
  172. data/test/benchmark/bm_caching.rb +0 -119
  173. data/test/benchmark/bm_transform.rb +0 -34
  174. data/test/benchmark/config.ru +0 -3
  175. data/test/benchmark/controllers.rb +0 -84
  176. data/test/benchmark/fixtures.rb +0 -219
  177. data/test/cache_test.rb +0 -485
  178. data/test/collection_serializer_test.rb +0 -110
  179. data/test/fixtures/active_record.rb +0 -78
  180. data/test/fixtures/poro.rb +0 -282
  181. data/test/generators/scaffold_controller_generator_test.rb +0 -24
  182. data/test/generators/serializer_generator_test.rb +0 -57
  183. data/test/grape_test.rb +0 -82
  184. data/test/include_tree/from_include_args_test.rb +0 -26
  185. data/test/include_tree/from_string_test.rb +0 -94
  186. data/test/include_tree/include_args_to_hash_test.rb +0 -64
  187. data/test/lint_test.rb +0 -49
  188. data/test/logger_test.rb +0 -18
  189. data/test/poro_test.rb +0 -9
  190. data/test/serializable_resource_test.rb +0 -83
  191. data/test/serializers/association_macros_test.rb +0 -36
  192. data/test/serializers/associations_test.rb +0 -295
  193. data/test/serializers/attribute_test.rb +0 -151
  194. data/test/serializers/attributes_test.rb +0 -52
  195. data/test/serializers/caching_configuration_test_isolated.rb +0 -170
  196. data/test/serializers/configuration_test.rb +0 -32
  197. data/test/serializers/fieldset_test.rb +0 -14
  198. data/test/serializers/meta_test.rb +0 -196
  199. data/test/serializers/options_test.rb +0 -21
  200. data/test/serializers/read_attribute_for_serialization_test.rb +0 -79
  201. data/test/serializers/root_test.rb +0 -21
  202. data/test/serializers/serialization_test.rb +0 -55
  203. data/test/serializers/serializer_for_test.rb +0 -134
  204. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +0 -6
  205. data/test/support/isolated_unit.rb +0 -79
  206. data/test/support/rails5_shims.rb +0 -47
  207. data/test/support/rails_app.rb +0 -45
  208. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +0 -6
  209. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +0 -6
  210. data/test/support/schemas/custom/show.json +0 -7
  211. data/test/support/schemas/hyper_schema.json +0 -93
  212. data/test/support/schemas/render_using_json_api.json +0 -43
  213. data/test/support/schemas/simple_json_pointers.json +0 -10
  214. data/test/support/serialization_testing.rb +0 -53
  215. data/test/test_helper.rb +0 -57
@@ -1,4 +1,6 @@
1
- require 'active_model_serializers/key_transform'
1
+ # frozen_string_literal: true
2
+
3
+ require 'case_transform'
2
4
 
3
5
  module ActiveModelSerializers
4
6
  module Adapter
@@ -8,6 +10,40 @@ module ActiveModelSerializers
8
10
  ActiveModelSerializers::Adapter.register(subclass)
9
11
  end
10
12
 
13
+ # Sets the default transform for the adapter.
14
+ #
15
+ # @return [Symbol] the default transform for the adapter
16
+ def self.default_key_transform
17
+ :unaltered
18
+ end
19
+
20
+ # Determines the transform to use in order of precedence:
21
+ # adapter option, global config, adapter default.
22
+ #
23
+ # @param options [Object]
24
+ # @return [Symbol] the transform to use
25
+ def self.transform(options)
26
+ return options[:key_transform] if options && options[:key_transform]
27
+ ActiveModelSerializers.config.key_transform || default_key_transform
28
+ end
29
+
30
+ # Transforms the casing of the supplied value.
31
+ #
32
+ # @param value [Object] the value to be transformed
33
+ # @param options [Object] serializable resource options
34
+ # @return [Symbol] the default transform for the adapter
35
+ def self.transform_key_casing!(value, options)
36
+ CaseTransform.send(transform(options), value)
37
+ end
38
+
39
+ def self.cache_key
40
+ @cache_key ||= ActiveModelSerializers::Adapter.registered_name(self)
41
+ end
42
+
43
+ def self.fragment_cache(cached_hash, non_cached_hash)
44
+ non_cached_hash.merge cached_hash
45
+ end
46
+
11
47
  attr_reader :serializer, :instance_options
12
48
 
13
49
  def initialize(serializer, options = {})
@@ -15,10 +51,6 @@ module ActiveModelSerializers
15
51
  @instance_options = options
16
52
  end
17
53
 
18
- def cached_name
19
- @cached_name ||= self.class.name.demodulize.underscore
20
- end
21
-
22
54
  # Subclasses that implement this method must first call
23
55
  # options = serialization_options(options)
24
56
  def serializable_hash(_options = nil)
@@ -29,14 +61,12 @@ module ActiveModelSerializers
29
61
  serializable_hash(options)
30
62
  end
31
63
 
32
- def fragment_cache(cached_hash, non_cached_hash)
33
- non_cached_hash.merge cached_hash
64
+ def cache_key
65
+ self.class.cache_key
34
66
  end
35
67
 
36
- def cache_check(serializer)
37
- serializer.cache_check(self) do
38
- yield
39
- end
68
+ def fragment_cache(cached_hash, non_cached_hash)
69
+ self.class.fragment_cache(cached_hash, non_cached_hash)
40
70
  end
41
71
 
42
72
  private
@@ -50,34 +80,6 @@ module ActiveModelSerializers
50
80
  def root
51
81
  serializer.json_key.to_sym if serializer.json_key
52
82
  end
53
-
54
- class << self
55
- # Sets the default transform for the adapter.
56
- #
57
- # @return [Symbol] the default transform for the adapter
58
- def default_key_transform
59
- :unaltered
60
- end
61
-
62
- # Determines the transform to use in order of precedence:
63
- # adapter option, global config, adapter default.
64
- #
65
- # @param options [Object]
66
- # @return [Symbol] the transform to use
67
- def transform(options)
68
- return options[:key_transform] if options && options[:key_transform]
69
- ActiveModelSerializers.config.key_transform || default_key_transform
70
- end
71
-
72
- # Transforms the casing of the supplied value.
73
- #
74
- # @param value [Object] the value to be transformed
75
- # @param options [Object] serializable resource options
76
- # @return [Symbol] the default transform for the adapter
77
- def transform_key_casing!(value, options)
78
- KeyTransform.send(transform(options), value)
79
- end
80
- end
81
83
  end
82
84
  end
83
85
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModelSerializers
2
4
  module Adapter
3
5
  class Json < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModelSerializers
2
4
  module Adapter
3
5
  class JsonApi
@@ -189,7 +191,7 @@ module ActiveModelSerializers
189
191
 
190
192
  polymorphic = (options[:polymorphic] || []).include?(assoc_name.to_sym)
191
193
  if polymorphic
192
- hash["#{prefix_key}_type".to_sym] = assoc_data.present? ? assoc_data['type'] : nil
194
+ hash["#{prefix_key}_type".to_sym] = assoc_data.present? ? assoc_data['type'].classify : nil
193
195
  end
194
196
 
195
197
  hash
@@ -205,7 +207,7 @@ module ActiveModelSerializers
205
207
  # @api private
206
208
  def transform_keys(hash, options)
207
209
  transform = options[:key_transform] || :underscore
208
- KeyTransform.send(transform, hash)
210
+ CaseTransform.send(transform, hash)
209
211
  end
210
212
  end
211
213
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModelSerializers
2
4
  module Adapter
3
5
  class JsonApi < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModelSerializers
2
4
  module Adapter
3
5
  class JsonApi < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModelSerializers
2
4
  module Adapter
3
5
  class JsonApi
@@ -71,7 +73,7 @@ module ActiveModelSerializers
71
73
  hash[:href] = @href if defined?(@href)
72
74
  hash[:meta] = @meta if defined?(@meta)
73
75
 
74
- hash
76
+ hash.any? ? hash : nil
75
77
  end
76
78
 
77
79
  protected
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModelSerializers
2
4
  module Adapter
3
5
  class JsonApi
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModelSerializers
2
4
  module Adapter
3
5
  class JsonApi < Base
4
6
  class PaginationLinks
7
+ MissingSerializationContextError = Class.new(KeyError)
5
8
  FIRST_PAGE = 1
6
9
 
7
10
  attr_reader :collection, :context
@@ -9,16 +12,23 @@ module ActiveModelSerializers
9
12
  def initialize(collection, adapter_options)
10
13
  @collection = collection
11
14
  @adapter_options = adapter_options
12
- @context = adapter_options.fetch(:serialization_context)
15
+ @context = adapter_options.fetch(:serialization_context) do
16
+ fail MissingSerializationContextError, <<-EOF.freeze
17
+ JsonApi::PaginationLinks requires a ActiveModelSerializers::SerializationContext.
18
+ Please pass a ':serialization_context' option or
19
+ override CollectionSerializer#paginated? to return 'false'.
20
+ EOF
21
+ end
13
22
  end
14
23
 
15
24
  def as_json
16
- per_page = collection.try(:per_page) || collection.try(:limit_value) || collection.size
17
- pages_from.each_with_object({}) do |(key, value), hash|
18
- params = query_parameters.merge(page: { number: value, size: per_page }).to_query
19
-
20
- hash[key] = "#{url(adapter_options)}?#{params}"
21
- end
25
+ {
26
+ self: location_url,
27
+ first: first_page_url,
28
+ prev: prev_page_url,
29
+ next: next_page_url,
30
+ last: last_page_url
31
+ }
22
32
  end
23
33
 
24
34
  protected
@@ -27,25 +37,39 @@ module ActiveModelSerializers
27
37
 
28
38
  private
29
39
 
30
- def pages_from
31
- return {} if collection.total_pages <= FIRST_PAGE
32
-
33
- {}.tap do |pages|
34
- pages[:self] = collection.current_page
40
+ def location_url
41
+ url_for_page(collection.current_page)
42
+ end
35
43
 
36
- unless collection.current_page == FIRST_PAGE
37
- pages[:first] = FIRST_PAGE
38
- pages[:prev] = collection.current_page - FIRST_PAGE
39
- end
44
+ def first_page_url
45
+ url_for_page(1)
46
+ end
40
47
 
41
- unless collection.current_page == collection.total_pages
42
- pages[:next] = collection.current_page + FIRST_PAGE
43
- pages[:last] = collection.total_pages
44
- end
48
+ def last_page_url
49
+ if collection.total_pages == 0
50
+ url_for_page(FIRST_PAGE)
51
+ else
52
+ url_for_page(collection.total_pages)
45
53
  end
46
54
  end
47
55
 
48
- def url(options)
56
+ def prev_page_url
57
+ return nil if collection.current_page == FIRST_PAGE
58
+ url_for_page(collection.current_page - FIRST_PAGE)
59
+ end
60
+
61
+ def next_page_url
62
+ return nil if collection.total_pages == 0 || collection.current_page == collection.total_pages
63
+ url_for_page(collection.next_page)
64
+ end
65
+
66
+ def url_for_page(number)
67
+ params = query_parameters.dup
68
+ params[:page] = { size: per_page, number: number }
69
+ "#{url(adapter_options)}?#{params.to_query}"
70
+ end
71
+
72
+ def url(options = {})
49
73
  @url ||= options.fetch(:links, {}).fetch(:self, nil) || request_url
50
74
  end
51
75
 
@@ -56,6 +80,10 @@ module ActiveModelSerializers
56
80
  def query_parameters
57
81
  @query_parameters ||= context.query_parameters
58
82
  end
83
+
84
+ def per_page
85
+ @per_page ||= collection.try(:per_page) || collection.try(:limit_value) || collection.size
86
+ end
59
87
  end
60
88
  end
61
89
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModelSerializers
2
4
  module Adapter
3
5
  class JsonApi
@@ -5,47 +7,99 @@ module ActiveModelSerializers
5
7
  # {http://jsonapi.org/format/#document-resource-object-related-resource-links Document Resource Object Related Resource Links}
6
8
  # {http://jsonapi.org/format/#document-links Document Links}
7
9
  # {http://jsonapi.org/format/#document-resource-object-linkage Document Resource Relationship Linkage}
8
- # {http://jsonapi.org/format/#document-meta Docment Meta}
9
- def initialize(parent_serializer, serializer, serializable_resource_options, args = {})
10
- @object = parent_serializer.object
11
- @scope = parent_serializer.scope
12
- @association_options = args.fetch(:options, {})
10
+ # {http://jsonapi.org/format/#document-meta Document Meta}
11
+ def initialize(parent_serializer, serializable_resource_options, association)
12
+ @parent_serializer = parent_serializer
13
+ @association = association
13
14
  @serializable_resource_options = serializable_resource_options
14
- @data = data_for(serializer)
15
- @links = args.fetch(:links, {}).each_with_object({}) do |(key, value), hash|
16
- hash[key] = ActiveModelSerializers::Adapter::JsonApi::Link.new(parent_serializer, value).as_json
17
- end
18
- meta = args.fetch(:meta, nil)
19
- @meta = meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta
20
15
  end
21
16
 
22
17
  def as_json
23
18
  hash = {}
24
- hash[:data] = data if association_options[:include_data]
25
- links = self.links
19
+
20
+ hash[:data] = data_for(association) if association.include_data?
21
+
22
+ links = links_for(association)
26
23
  hash[:links] = links if links.any?
27
- meta = self.meta
24
+
25
+ meta = meta_for(association)
28
26
  hash[:meta] = meta if meta
27
+ hash[:meta] = {} if hash.empty?
29
28
 
30
29
  hash
31
30
  end
32
31
 
33
32
  protected
34
33
 
35
- attr_reader :object, :scope, :data, :serializable_resource_options,
36
- :association_options, :links, :meta
34
+ attr_reader :parent_serializer, :serializable_resource_options, :association
37
35
 
38
36
  private
39
37
 
40
- def data_for(serializer)
41
- if serializer.respond_to?(:each)
42
- serializer.map { |s| ResourceIdentifier.new(s, serializable_resource_options).as_json }
43
- elsif association_options[:virtual_value]
44
- association_options[:virtual_value]
45
- elsif serializer && serializer.object
46
- ResourceIdentifier.new(serializer, serializable_resource_options).as_json
38
+ # TODO(BF): Avoid db hit on belong_to_ releationship by using foreign_key on self
39
+ def data_for(association)
40
+ if association.collection?
41
+ data_for_many(association)
42
+ else
43
+ data_for_one(association)
44
+ end
45
+ end
46
+
47
+ def data_for_one(association)
48
+ if belongs_to_id_on_self?(association)
49
+ id = parent_serializer.read_attribute_for_serialization(association.reflection.foreign_key)
50
+ type =
51
+ if association.polymorphic?
52
+ # We can't infer resource type for polymorphic relationships from the serializer.
53
+ # We can ONLY know a polymorphic resource type by inspecting each resource.
54
+ association.lazy_association.serializer.json_key
55
+ else
56
+ association.reflection.type.to_s
57
+ end
58
+ ResourceIdentifier.for_type_with_id(type, id, serializable_resource_options)
59
+ else
60
+ # TODO(BF): Process relationship without evaluating lazy_association
61
+ serializer = association.lazy_association.serializer
62
+ if (virtual_value = association.virtual_value)
63
+ virtual_value
64
+ elsif serializer && association.object
65
+ ResourceIdentifier.new(serializer, serializable_resource_options).as_json
66
+ else
67
+ nil
68
+ end
69
+ end
70
+ end
71
+
72
+ def data_for_many(association)
73
+ # TODO(BF): Process relationship without evaluating lazy_association
74
+ collection_serializer = association.lazy_association.serializer
75
+ if collection_serializer.respond_to?(:each)
76
+ collection_serializer.map do |serializer|
77
+ ResourceIdentifier.new(serializer, serializable_resource_options).as_json
78
+ end
79
+ elsif (virtual_value = association.virtual_value)
80
+ virtual_value
81
+ else
82
+ []
83
+ end
84
+ end
85
+
86
+ def links_for(association)
87
+ association.links.each_with_object({}) do |(key, value), hash|
88
+ result = Link.new(parent_serializer, value).as_json
89
+ hash[key] = result if result
47
90
  end
48
91
  end
92
+
93
+ def meta_for(association)
94
+ meta = association.meta
95
+ meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta
96
+ end
97
+
98
+ def belongs_to_id_on_self?(association)
99
+ parent_serializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship &&
100
+ association.belongs_to? &&
101
+ parent_serializer.object.respond_to?(association.reflection.foreign_key)
102
+ end
49
103
  end
50
104
  end
51
105
  end
@@ -1,16 +1,51 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModelSerializers
2
4
  module Adapter
3
5
  class JsonApi
4
6
  class ResourceIdentifier
7
+ def self.type_for(serializer, serializer_type = nil, transform_options = {})
8
+ raw_type = serializer_type ? serializer_type : raw_type_from_serializer_object(serializer.object)
9
+ JsonApi.send(:transform_key_casing!, raw_type, transform_options)
10
+ end
11
+
12
+ def self.for_type_with_id(type, id, options)
13
+ type = inflect_type(type)
14
+ type = type_for(:no_class_needed, type, options)
15
+ if id.blank?
16
+ nil
17
+ else
18
+ { id: id.to_s, type: type }
19
+ end
20
+ end
21
+
22
+ def self.raw_type_from_serializer_object(object)
23
+ class_name = object.class.name # should use model_name
24
+ raw_type = class_name.underscore
25
+ raw_type = inflect_type(raw_type)
26
+ raw_type
27
+ .gsub!('/'.freeze, ActiveModelSerializers.config.jsonapi_namespace_separator)
28
+ raw_type
29
+ end
30
+
31
+ def self.inflect_type(type)
32
+ singularize = ActiveModelSerializers.config.jsonapi_resource_type == :singular
33
+ inflection = singularize ? :singularize : :pluralize
34
+ ActiveSupport::Inflector.public_send(inflection, type)
35
+ end
36
+
5
37
  # {http://jsonapi.org/format/#document-resource-identifier-objects Resource Identifier Objects}
6
38
  def initialize(serializer, options)
7
39
  @id = id_for(serializer)
8
- @type = JsonApi.send(:transform_key_casing!, type_for(serializer),
9
- options)
40
+ @type = type_for(serializer, options)
10
41
  end
11
42
 
12
43
  def as_json
13
- { id: id, type: type }
44
+ if id.blank?
45
+ { type: type }
46
+ else
47
+ { id: id.to_s, type: type }
48
+ end
14
49
  end
15
50
 
16
51
  protected
@@ -19,13 +54,9 @@ module ActiveModelSerializers
19
54
 
20
55
  private
21
56
 
22
- def type_for(serializer)
23
- return serializer._type if serializer._type
24
- if ActiveModelSerializers.config.jsonapi_resource_type == :singular
25
- serializer.object.class.model_name.singular
26
- else
27
- serializer.object.class.model_name.plural
28
- end
57
+ def type_for(serializer, transform_options)
58
+ serializer_type = serializer._type
59
+ self.class.type_for(serializer, serializer_type, transform_options)
29
60
  end
30
61
 
31
62
  def id_for(serializer)