active_model_serializers 0.10.7 → 0.10.12

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 (213) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +62 -1
  3. data/README.md +20 -20
  4. data/lib/action_controller/serialization.rb +11 -1
  5. data/lib/active_model/serializable_resource.rb +2 -0
  6. data/lib/active_model/serializer.rb +33 -18
  7. data/lib/active_model/serializer/adapter.rb +2 -0
  8. data/lib/active_model/serializer/adapter/attributes.rb +2 -0
  9. data/lib/active_model/serializer/adapter/base.rb +2 -0
  10. data/lib/active_model/serializer/adapter/json.rb +2 -0
  11. data/lib/active_model/serializer/adapter/json_api.rb +2 -0
  12. data/lib/active_model/serializer/adapter/null.rb +2 -0
  13. data/lib/active_model/serializer/array_serializer.rb +2 -0
  14. data/lib/active_model/serializer/association.rb +2 -0
  15. data/lib/active_model/serializer/attribute.rb +2 -0
  16. data/lib/active_model/serializer/belongs_to_reflection.rb +2 -0
  17. data/lib/active_model/serializer/collection_serializer.rb +6 -6
  18. data/lib/active_model/serializer/concerns/caching.rb +7 -2
  19. data/lib/active_model/serializer/error_serializer.rb +2 -0
  20. data/lib/active_model/serializer/errors_serializer.rb +2 -0
  21. data/lib/active_model/serializer/field.rb +2 -0
  22. data/lib/active_model/serializer/fieldset.rb +3 -1
  23. data/lib/active_model/serializer/has_many_reflection.rb +2 -0
  24. data/lib/active_model/serializer/has_one_reflection.rb +2 -0
  25. data/lib/active_model/serializer/lazy_association.rb +6 -2
  26. data/lib/active_model/serializer/link.rb +23 -0
  27. data/lib/active_model/serializer/lint.rb +2 -0
  28. data/lib/active_model/serializer/null.rb +2 -0
  29. data/lib/active_model/serializer/reflection.rb +9 -4
  30. data/lib/active_model/serializer/version.rb +3 -1
  31. data/lib/active_model_serializers.rb +20 -10
  32. data/lib/active_model_serializers/adapter.rb +3 -1
  33. data/lib/active_model_serializers/adapter/attributes.rb +23 -0
  34. data/lib/active_model_serializers/adapter/base.rb +2 -0
  35. data/lib/active_model_serializers/adapter/json.rb +2 -0
  36. data/lib/active_model_serializers/adapter/json_api.rb +14 -9
  37. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +2 -0
  38. data/lib/active_model_serializers/adapter/json_api/error.rb +2 -0
  39. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +2 -0
  40. data/lib/active_model_serializers/adapter/json_api/link.rb +2 -0
  41. data/lib/active_model_serializers/adapter/json_api/meta.rb +2 -0
  42. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +2 -0
  43. data/lib/active_model_serializers/adapter/json_api/relationship.rb +2 -0
  44. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +3 -1
  45. data/lib/active_model_serializers/adapter/null.rb +2 -0
  46. data/lib/active_model_serializers/callbacks.rb +2 -0
  47. data/lib/active_model_serializers/deprecate.rb +2 -0
  48. data/lib/active_model_serializers/deserialization.rb +2 -0
  49. data/lib/active_model_serializers/json_pointer.rb +2 -0
  50. data/lib/active_model_serializers/logging.rb +2 -0
  51. data/lib/active_model_serializers/lookup_chain.rb +2 -0
  52. data/lib/active_model_serializers/model.rb +2 -0
  53. data/lib/active_model_serializers/model/caching.rb +25 -0
  54. data/lib/active_model_serializers/railtie.rb +4 -0
  55. data/lib/active_model_serializers/register_jsonapi_renderer.rb +2 -0
  56. data/lib/active_model_serializers/serializable_resource.rb +4 -2
  57. data/lib/active_model_serializers/serialization_context.rb +2 -0
  58. data/lib/active_model_serializers/test.rb +2 -0
  59. data/lib/active_model_serializers/test/schema.rb +2 -0
  60. data/lib/active_model_serializers/test/serializer.rb +2 -0
  61. data/lib/generators/rails/resource_override.rb +2 -0
  62. data/lib/generators/rails/serializer_generator.rb +2 -0
  63. data/lib/grape/active_model_serializers.rb +2 -0
  64. data/lib/grape/formatters/active_model_serializers.rb +2 -0
  65. data/lib/grape/helpers/active_model_serializers.rb +2 -0
  66. data/lib/tasks/rubocop.rake +2 -0
  67. metadata +70 -295
  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 -105
  72. data/.simplecov +0 -110
  73. data/.travis.yml +0 -52
  74. data/CODE_OF_CONDUCT.md +0 -74
  75. data/CONTRIBUTING.md +0 -105
  76. data/Gemfile +0 -72
  77. data/Rakefile +0 -74
  78. data/active_model_serializers.gemspec +0 -63
  79. data/appveyor.yml +0 -28
  80. data/bin/bench +0 -171
  81. data/bin/bench_regression +0 -316
  82. data/bin/rubocop +0 -38
  83. data/bin/serve_benchmark +0 -39
  84. data/docs/README.md +0 -41
  85. data/docs/STYLE.md +0 -58
  86. data/docs/general/adapters.md +0 -269
  87. data/docs/general/caching.md +0 -58
  88. data/docs/general/configuration_options.md +0 -185
  89. data/docs/general/deserialization.md +0 -100
  90. data/docs/general/fields.md +0 -31
  91. data/docs/general/getting_started.md +0 -133
  92. data/docs/general/instrumentation.md +0 -40
  93. data/docs/general/key_transforms.md +0 -40
  94. data/docs/general/logging.md +0 -21
  95. data/docs/general/rendering.md +0 -293
  96. data/docs/general/serializers.md +0 -483
  97. data/docs/how-open-source-maintained.jpg +0 -0
  98. data/docs/howto/add_pagination_links.md +0 -138
  99. data/docs/howto/add_relationship_links.md +0 -140
  100. data/docs/howto/add_root_key.md +0 -62
  101. data/docs/howto/grape_integration.md +0 -42
  102. data/docs/howto/outside_controller_use.md +0 -66
  103. data/docs/howto/passing_arbitrary_options.md +0 -27
  104. data/docs/howto/serialize_poro.md +0 -73
  105. data/docs/howto/test.md +0 -154
  106. data/docs/howto/upgrade_from_0_8_to_0_10.md +0 -265
  107. data/docs/integrations/ember-and-json-api.md +0 -147
  108. data/docs/integrations/grape.md +0 -19
  109. data/docs/jsonapi/errors.md +0 -56
  110. data/docs/jsonapi/schema.md +0 -151
  111. data/docs/jsonapi/schema/schema.json +0 -366
  112. data/docs/rfcs/0000-namespace.md +0 -106
  113. data/docs/rfcs/template.md +0 -15
  114. data/test/action_controller/adapter_selector_test.rb +0 -62
  115. data/test/action_controller/explicit_serializer_test.rb +0 -135
  116. data/test/action_controller/json/include_test.rb +0 -246
  117. data/test/action_controller/json_api/deserialization_test.rb +0 -112
  118. data/test/action_controller/json_api/errors_test.rb +0 -40
  119. data/test/action_controller/json_api/fields_test.rb +0 -66
  120. data/test/action_controller/json_api/linked_test.rb +0 -202
  121. data/test/action_controller/json_api/pagination_test.rb +0 -124
  122. data/test/action_controller/json_api/transform_test.rb +0 -189
  123. data/test/action_controller/lookup_proc_test.rb +0 -49
  124. data/test/action_controller/namespace_lookup_test.rb +0 -232
  125. data/test/action_controller/serialization_scope_name_test.rb +0 -235
  126. data/test/action_controller/serialization_test.rb +0 -472
  127. data/test/active_model_serializers/adapter_for_test.rb +0 -208
  128. data/test/active_model_serializers/json_pointer_test.rb +0 -22
  129. data/test/active_model_serializers/logging_test.rb +0 -77
  130. data/test/active_model_serializers/model_test.rb +0 -142
  131. data/test/active_model_serializers/railtie_test_isolated.rb +0 -68
  132. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +0 -161
  133. data/test/active_model_serializers/serialization_context_test_isolated.rb +0 -71
  134. data/test/active_model_serializers/test/schema_test.rb +0 -131
  135. data/test/active_model_serializers/test/serializer_test.rb +0 -62
  136. data/test/active_record_test.rb +0 -9
  137. data/test/adapter/attributes_test.rb +0 -40
  138. data/test/adapter/deprecation_test.rb +0 -100
  139. data/test/adapter/json/belongs_to_test.rb +0 -45
  140. data/test/adapter/json/collection_test.rb +0 -104
  141. data/test/adapter/json/has_many_test.rb +0 -53
  142. data/test/adapter/json/transform_test.rb +0 -93
  143. data/test/adapter/json_api/belongs_to_test.rb +0 -155
  144. data/test/adapter/json_api/collection_test.rb +0 -96
  145. data/test/adapter/json_api/errors_test.rb +0 -76
  146. data/test/adapter/json_api/fields_test.rb +0 -96
  147. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +0 -96
  148. data/test/adapter/json_api/has_many_test.rb +0 -173
  149. data/test/adapter/json_api/has_one_test.rb +0 -80
  150. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +0 -213
  151. data/test/adapter/json_api/json_api_test.rb +0 -33
  152. data/test/adapter/json_api/linked_test.rb +0 -413
  153. data/test/adapter/json_api/links_test.rb +0 -95
  154. data/test/adapter/json_api/pagination_links_test.rb +0 -206
  155. data/test/adapter/json_api/parse_test.rb +0 -137
  156. data/test/adapter/json_api/relationship_test.rb +0 -397
  157. data/test/adapter/json_api/resource_meta_test.rb +0 -100
  158. data/test/adapter/json_api/toplevel_jsonapi_test.rb +0 -82
  159. data/test/adapter/json_api/transform_test.rb +0 -512
  160. data/test/adapter/json_api/type_test.rb +0 -193
  161. data/test/adapter/json_test.rb +0 -46
  162. data/test/adapter/null_test.rb +0 -22
  163. data/test/adapter/polymorphic_test.rb +0 -218
  164. data/test/adapter_test.rb +0 -67
  165. data/test/array_serializer_test.rb +0 -22
  166. data/test/benchmark/app.rb +0 -65
  167. data/test/benchmark/benchmarking_support.rb +0 -67
  168. data/test/benchmark/bm_active_record.rb +0 -81
  169. data/test/benchmark/bm_adapter.rb +0 -38
  170. data/test/benchmark/bm_caching.rb +0 -119
  171. data/test/benchmark/bm_lookup_chain.rb +0 -83
  172. data/test/benchmark/bm_transform.rb +0 -45
  173. data/test/benchmark/config.ru +0 -3
  174. data/test/benchmark/controllers.rb +0 -83
  175. data/test/benchmark/fixtures.rb +0 -219
  176. data/test/cache_test.rb +0 -651
  177. data/test/collection_serializer_test.rb +0 -127
  178. data/test/fixtures/active_record.rb +0 -113
  179. data/test/fixtures/poro.rb +0 -225
  180. data/test/generators/scaffold_controller_generator_test.rb +0 -24
  181. data/test/generators/serializer_generator_test.rb +0 -75
  182. data/test/grape_test.rb +0 -196
  183. data/test/lint_test.rb +0 -49
  184. data/test/logger_test.rb +0 -20
  185. data/test/poro_test.rb +0 -9
  186. data/test/serializable_resource_test.rb +0 -79
  187. data/test/serializers/association_macros_test.rb +0 -37
  188. data/test/serializers/associations_test.rb +0 -468
  189. data/test/serializers/attribute_test.rb +0 -153
  190. data/test/serializers/attributes_test.rb +0 -52
  191. data/test/serializers/caching_configuration_test_isolated.rb +0 -170
  192. data/test/serializers/configuration_test.rb +0 -32
  193. data/test/serializers/fieldset_test.rb +0 -14
  194. data/test/serializers/meta_test.rb +0 -202
  195. data/test/serializers/options_test.rb +0 -32
  196. data/test/serializers/read_attribute_for_serialization_test.rb +0 -79
  197. data/test/serializers/reflection_test.rb +0 -427
  198. data/test/serializers/root_test.rb +0 -21
  199. data/test/serializers/serialization_test.rb +0 -55
  200. data/test/serializers/serializer_for_test.rb +0 -136
  201. data/test/serializers/serializer_for_with_namespace_test.rb +0 -88
  202. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +0 -6
  203. data/test/support/isolated_unit.rb +0 -84
  204. data/test/support/rails5_shims.rb +0 -53
  205. data/test/support/rails_app.rb +0 -38
  206. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +0 -6
  207. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +0 -6
  208. data/test/support/schemas/custom/show.json +0 -7
  209. data/test/support/schemas/hyper_schema.json +0 -93
  210. data/test/support/schemas/render_using_json_api.json +0 -43
  211. data/test/support/schemas/simple_json_pointers.json +0 -10
  212. data/test/support/serialization_testing.rb +0 -79
  213. data/test/test_helper.rb +0 -70
@@ -1,83 +0,0 @@
1
- require_relative './benchmarking_support'
2
- require_relative './app'
3
-
4
- time = 10
5
- disable_gc = true
6
- ActiveModelSerializers.config.key_transform = :unaltered
7
-
8
- module AmsBench
9
- module Api
10
- module V1
11
- class PrimaryResourceSerializer < ActiveModel::Serializer
12
- attributes :title, :body
13
-
14
- has_many :has_many_relationships
15
- end
16
-
17
- class HasManyRelationshipSerializer < ActiveModel::Serializer
18
- attribute :body
19
- end
20
- end
21
- end
22
- class PrimaryResourceSerializer < ActiveModel::Serializer
23
- attributes :title, :body
24
-
25
- has_many :has_many_relationships
26
-
27
- class HasManyRelationshipSerializer < ActiveModel::Serializer
28
- attribute :body
29
- end
30
- end
31
- end
32
-
33
- resource = PrimaryResource.new(
34
- id: 1,
35
- title: 'title',
36
- body: 'body',
37
- has_many_relationships: [
38
- HasManyRelationship.new(id: 1, body: 'body1'),
39
- HasManyRelationship.new(id: 2, body: 'body1')
40
- ]
41
- )
42
-
43
- serialization = lambda do
44
- ActiveModelSerializers::SerializableResource.new(resource, serializer: AmsBench::PrimaryResourceSerializer).as_json
45
- ActiveModelSerializers::SerializableResource.new(resource, namespace: AmsBench::Api::V1).as_json
46
- ActiveModelSerializers::SerializableResource.new(resource).as_json
47
- end
48
-
49
- def clear_cache
50
- AmsBench::PrimaryResourceSerializer.serializers_cache.clear
51
- AmsBench::Api::V1::PrimaryResourceSerializer.serializers_cache.clear
52
- ActiveModel::Serializer.serializers_cache.clear
53
- end
54
-
55
- configurable = lambda do
56
- clear_cache
57
- Benchmark.ams('Configurable Lookup Chain', time: time, disable_gc: disable_gc, &serialization)
58
- end
59
-
60
- old = lambda do
61
- clear_cache
62
- module ActiveModel
63
- class Serializer
64
- def self.serializer_lookup_chain_for(klass, namespace = nil)
65
- chain = []
66
-
67
- resource_class_name = klass.name.demodulize
68
- resource_namespace = klass.name.deconstantize
69
- serializer_class_name = "#{resource_class_name}Serializer"
70
-
71
- chain.push("#{namespace}::#{serializer_class_name}") if namespace
72
- chain.push("#{name}::#{serializer_class_name}") if self != ActiveModel::Serializer
73
- chain.push("#{resource_namespace}::#{serializer_class_name}")
74
- chain
75
- end
76
- end
77
- end
78
-
79
- Benchmark.ams('Old Lookup Chain (v0.10)', time: time, disable_gc: disable_gc, &serialization)
80
- end
81
-
82
- configurable.call
83
- old.call
@@ -1,45 +0,0 @@
1
- require_relative './benchmarking_support'
2
- require_relative './app'
3
-
4
- time = 10
5
- disable_gc = true
6
- ActiveModelSerializers.config.key_transform = :unaltered
7
- has_many_relationships = (0..50).map do |i|
8
- HasManyRelationship.new(id: i, body: 'ZOMG A HAS MANY RELATIONSHIP')
9
- end
10
- has_one_relationship = HasOneRelationship.new(
11
- id: 42,
12
- first_name: 'Joao',
13
- last_name: 'Moura'
14
- )
15
- primary_resource = PrimaryResource.new(
16
- id: 1337,
17
- title: 'New PrimaryResource',
18
- virtual_attribute: nil,
19
- body: 'Body',
20
- has_many_relationships: has_many_relationships,
21
- has_one_relationship: has_one_relationship
22
- )
23
- serializer = PrimaryResourceSerializer.new(primary_resource)
24
- adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
25
- serialization = adapter.as_json
26
-
27
- Benchmark.ams('camel', time: time, disable_gc: disable_gc) do
28
- CaseTransform.camel(serialization)
29
- end
30
-
31
- Benchmark.ams('camel_lower', time: time, disable_gc: disable_gc) do
32
- CaseTransform.camel_lower(serialization)
33
- end
34
-
35
- Benchmark.ams('dash', time: time, disable_gc: disable_gc) do
36
- CaseTransform.dash(serialization)
37
- end
38
-
39
- Benchmark.ams('unaltered', time: time, disable_gc: disable_gc) do
40
- CaseTransform.unaltered(serialization)
41
- end
42
-
43
- Benchmark.ams('underscore', time: time, disable_gc: disable_gc) do
44
- CaseTransform.underscore(serialization)
45
- end
@@ -1,3 +0,0 @@
1
- require File.expand_path(['..', 'app'].join(File::SEPARATOR), __FILE__)
2
-
3
- run Rails.application
@@ -1,83 +0,0 @@
1
- class PrimaryResourceController < ActionController::Base
2
- PRIMARY_RESOURCE =
3
- begin
4
- if ENV['BENCH_STRESS']
5
- has_many_relationships = (0..50).map do |i|
6
- HasManyRelationship.new(id: i, body: 'ZOMG A HAS MANY RELATIONSHIP')
7
- end
8
- else
9
- has_many_relationships = [HasManyRelationship.new(id: 1, body: 'ZOMG A HAS MANY RELATIONSHIP')]
10
- end
11
- has_one_relationship = HasOneRelationship.new(id: 42, first_name: 'Joao', last_name: 'Moura')
12
- PrimaryResource.new(id: 1337, title: 'New PrimaryResource', virtual_attribute: nil, body: 'Body', has_many_relationships: has_many_relationships, has_one_relationship: has_one_relationship)
13
- end
14
-
15
- def render_with_caching_serializer
16
- toggle_cache_status
17
- render json: PRIMARY_RESOURCE, serializer: CachingPrimaryResourceSerializer, adapter: :json, meta: { caching: perform_caching }
18
- end
19
-
20
- def render_with_fragment_caching_serializer
21
- toggle_cache_status
22
- render json: PRIMARY_RESOURCE, serializer: FragmentCachingPrimaryResourceSerializer, adapter: :json, meta: { caching: perform_caching }
23
- end
24
-
25
- def render_with_non_caching_serializer
26
- toggle_cache_status
27
- render json: PRIMARY_RESOURCE, adapter: :json, meta: { caching: perform_caching }
28
- end
29
-
30
- def render_cache_status
31
- toggle_cache_status
32
- # Uncomment to debug
33
- # STDERR.puts cache_store.class
34
- # STDERR.puts cache_dependencies
35
- # ActiveSupport::Cache::Store.logger.debug [ActiveModelSerializers.config.cache_store, ActiveModelSerializers.config.perform_caching, CachingPrimaryResourceSerializer._cache, perform_caching, params].inspect
36
- render json: { caching: perform_caching, meta: { cache_log: cache_messages, cache_status: cache_status } }.to_json
37
- end
38
-
39
- def clear
40
- ActionController::Base.cache_store.clear
41
- # Test caching is on
42
- # Uncomment to turn on logger; possible performance issue
43
- # logger = BenchmarkLogger.new
44
- # ActiveSupport::Cache::Store.logger = logger # seems to be the best way
45
- #
46
- # the below is used in some rails tests but isn't available/working in all versions, so far as I can tell
47
- # https://github.com/rails/rails/pull/15943
48
- # ActiveSupport::Notifications.subscribe(/^cache_(.*)\.active_support$/) do |*args|
49
- # logger.debug ActiveSupport::Notifications::Event.new(*args)
50
- # end
51
- render json: 'ok'.to_json
52
- end
53
-
54
- private
55
-
56
- def cache_status
57
- {
58
- controller: perform_caching,
59
- app: Rails.configuration.action_controller.perform_caching,
60
- serializers: Rails.configuration.serializers.each_with_object({}) { |serializer, data| data[serializer.name] = serializer._cache.present? }
61
- }
62
- end
63
-
64
- def cache_messages
65
- ActiveSupport::Cache::Store.logger.is_a?(BenchmarkLogger) && ActiveSupport::Cache::Store.logger.messages.split("\n")
66
- end
67
-
68
- def toggle_cache_status
69
- case params[:on]
70
- when 'on'.freeze then self.perform_caching = true
71
- when 'off'.freeze then self.perform_caching = false
72
- else nil # no-op
73
- end
74
- end
75
- end
76
-
77
- Rails.application.routes.draw do
78
- get '/status(/:on)' => 'primary_resource#render_cache_status'
79
- get '/clear' => 'primary_resource#clear'
80
- get '/caching(/:on)' => 'primary_resource#render_with_caching_serializer'
81
- get '/fragment_caching(/:on)' => 'primary_resource#render_with_fragment_caching_serializer'
82
- get '/non_caching(/:on)' => 'primary_resource#render_with_non_caching_serializer'
83
- end
@@ -1,219 +0,0 @@
1
- Rails.configuration.serializers = []
2
- class HasOneRelationshipSerializer < ActiveModel::Serializer
3
- attributes :id, :first_name, :last_name
4
-
5
- has_many :primary_resources, embed: :ids
6
- has_one :bio
7
- end
8
- Rails.configuration.serializers << HasOneRelationshipSerializer
9
-
10
- class VirtualAttributeSerializer < ActiveModel::Serializer
11
- attributes :id, :name
12
- end
13
- Rails.configuration.serializers << VirtualAttributeSerializer
14
-
15
- class HasManyRelationshipSerializer < ActiveModel::Serializer
16
- attributes :id, :body
17
-
18
- belongs_to :primary_resource
19
- belongs_to :has_one_relationship
20
- end
21
- Rails.configuration.serializers << HasManyRelationshipSerializer
22
-
23
- class PrimaryResourceSerializer < ActiveModel::Serializer
24
- attributes :id, :title, :body
25
-
26
- has_many :has_many_relationships, serializer: HasManyRelationshipSerializer
27
- belongs_to :virtual_attribute, serializer: VirtualAttributeSerializer
28
- belongs_to :has_one_relationship, serializer: HasOneRelationshipSerializer
29
-
30
- link(:primary_resource_has_one_relationships) { 'https://example.com/primary_resource_has_one_relationships' }
31
-
32
- meta do
33
- {
34
- rating: 5,
35
- favorite_count: 10
36
- }
37
- end
38
-
39
- def virtual_attribute
40
- VirtualAttribute.new(id: 999, name: 'Free-Range Virtual Attribute')
41
- end
42
- end
43
- Rails.configuration.serializers << PrimaryResourceSerializer
44
-
45
- class CachingHasOneRelationshipSerializer < HasOneRelationshipSerializer
46
- cache key: 'writer', skip_digest: true
47
- end
48
- Rails.configuration.serializers << CachingHasOneRelationshipSerializer
49
-
50
- class CachingHasManyRelationshipSerializer < HasManyRelationshipSerializer
51
- cache expires_in: 1.day, skip_digest: true
52
- end
53
- Rails.configuration.serializers << CachingHasManyRelationshipSerializer
54
-
55
- # see https://github.com/rails-api/active_model_serializers/pull/1690/commits/68715b8f99bc29677e8a47bb3f305f23c077024b#r60344532
56
- class CachingPrimaryResourceSerializer < ActiveModel::Serializer
57
- cache key: 'primary_resource', expires_in: 0.1, skip_digest: true
58
-
59
- attributes :id, :title, :body
60
-
61
- belongs_to :virtual_attribute, serializer: VirtualAttributeSerializer
62
- belongs_to :has_one_relationship, serializer: CachingHasOneRelationshipSerializer
63
- has_many :has_many_relationships, serializer: CachingHasManyRelationshipSerializer
64
-
65
- link(:primary_resource_has_one_relationships) { 'https://example.com/primary_resource_has_one_relationships' }
66
-
67
- meta do
68
- {
69
- rating: 5,
70
- favorite_count: 10
71
- }
72
- end
73
-
74
- def virtual_attribute
75
- VirtualAttribute.new(id: 999, name: 'Free-Range Virtual Attribute')
76
- end
77
- end
78
- Rails.configuration.serializers << CachingPrimaryResourceSerializer
79
-
80
- class FragmentCachingHasOneRelationshipSerializer < HasOneRelationshipSerializer
81
- cache key: 'writer', only: [:first_name, :last_name], skip_digest: true
82
- end
83
- Rails.configuration.serializers << FragmentCachingHasOneRelationshipSerializer
84
-
85
- class FragmentCachingHasManyRelationshipSerializer < HasManyRelationshipSerializer
86
- cache expires_in: 1.day, except: [:body], skip_digest: true
87
- end
88
- Rails.configuration.serializers << CachingHasManyRelationshipSerializer
89
-
90
- # see https://github.com/rails-api/active_model_serializers/pull/1690/commits/68715b8f99bc29677e8a47bb3f305f23c077024b#r60344532
91
- class FragmentCachingPrimaryResourceSerializer < ActiveModel::Serializer
92
- cache key: 'primary_resource', expires_in: 0.1, skip_digest: true
93
-
94
- attributes :id, :title, :body
95
-
96
- belongs_to :virtual_attribute, serializer: VirtualAttributeSerializer
97
- belongs_to :has_one_relationship, serializer: FragmentCachingHasOneRelationshipSerializer
98
- has_many :has_many_relationships, serializer: FragmentCachingHasManyRelationshipSerializer
99
-
100
- link(:primary_resource_has_one_relationships) { 'https://example.com/primary_resource_has_one_relationships' }
101
-
102
- meta do
103
- {
104
- rating: 5,
105
- favorite_count: 10
106
- }
107
- end
108
-
109
- def virtual_attribute
110
- VirtualAttribute.new(id: 999, name: 'Free-Range Virtual Attribute')
111
- end
112
- end
113
- Rails.configuration.serializers << FragmentCachingPrimaryResourceSerializer
114
-
115
- if ENV['ENABLE_ACTIVE_RECORD'] == 'true'
116
- require 'active_record'
117
-
118
- ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
119
- ActiveRecord::Schema.define do
120
- self.verbose = false
121
-
122
- create_table :virtual_attributes, force: true do |t|
123
- t.string :name
124
- t.timestamps null: false
125
- end
126
- create_table :has_one_relationships, force: true do |t|
127
- t.string :first_name
128
- t.string :last_name
129
- t.timestamps null: false
130
- end
131
- create_table :primary_resources, force: true do |t|
132
- t.string :title
133
- t.text :body
134
- t.references :has_one_relationship
135
- t.references :virtual_attribute
136
- t.timestamps null: false
137
- end
138
- create_table :has_many_relationships, force: true do |t|
139
- t.text :body
140
- t.references :has_one_relationship
141
- t.references :primary_resource
142
- t.timestamps null: false
143
- end
144
- end
145
-
146
- class HasManyRelationship < ActiveRecord::Base
147
- belongs_to :has_one_relationship
148
- belongs_to :primary_resource
149
- end
150
-
151
- class HasOneRelationship < ActiveRecord::Base
152
- has_many :primary_resources
153
- has_many :has_many_relationships
154
- end
155
-
156
- class PrimaryResource < ActiveRecord::Base
157
- has_many :has_many_relationships
158
- belongs_to :has_one_relationship
159
- belongs_to :virtual_attribute
160
- end
161
-
162
- class VirtualAttribute < ActiveRecord::Base
163
- has_many :primary_resources
164
- end
165
- else
166
- # ActiveModelSerializers::Model is a convenient
167
- # serializable class to inherit from when making
168
- # serializable non-activerecord objects.
169
- class BenchmarkModel
170
- include ActiveModel::Model
171
- include ActiveModel::Serializers::JSON
172
-
173
- attr_reader :attributes
174
-
175
- def initialize(attributes = {})
176
- @attributes = attributes
177
- super
178
- end
179
-
180
- # Defaults to the downcased model name.
181
- def id
182
- attributes.fetch(:id) { self.class.name.downcase }
183
- end
184
-
185
- # Defaults to the downcased model name and updated_at
186
- def cache_key
187
- attributes.fetch(:cache_key) { "#{self.class.name.downcase}/#{id}" }
188
- end
189
-
190
- # Defaults to the time the serializer file was modified.
191
- def updated_at
192
- @updated_at ||= attributes.fetch(:updated_at) { File.mtime(__FILE__) }
193
- end
194
-
195
- def read_attribute_for_serialization(key)
196
- if key == :id || key == 'id'
197
- attributes.fetch(key) { id }
198
- else
199
- attributes[key]
200
- end
201
- end
202
- end
203
-
204
- class HasManyRelationship < BenchmarkModel
205
- attr_accessor :id, :body
206
- end
207
-
208
- class HasOneRelationship < BenchmarkModel
209
- attr_accessor :id, :first_name, :last_name, :primary_resources
210
- end
211
-
212
- class PrimaryResource < BenchmarkModel
213
- attr_accessor :id, :title, :body, :has_many_relationships, :virtual_attribute, :has_one_relationship
214
- end
215
-
216
- class VirtualAttribute < BenchmarkModel
217
- attr_accessor :id, :name
218
- end
219
- end
@@ -1,651 +0,0 @@
1
- require 'test_helper'
2
- require 'tmpdir'
3
- require 'tempfile'
4
-
5
- module ActiveModelSerializers
6
- class CacheTest < ActiveSupport::TestCase
7
- class Article < ::Model
8
- attributes :title
9
- # To confirm error is raised when cache_key is not set and cache_key option not passed to cache
10
- undef_method :cache_key
11
- end
12
- class ArticleSerializer < ActiveModel::Serializer
13
- cache only: [:place], skip_digest: true
14
- attributes :title
15
- end
16
-
17
- class Author < ::Model
18
- attributes :id, :name
19
- associations :posts, :bio, :roles
20
- end
21
- # Instead of a primitive cache key (i.e. a string), this class
22
- # returns a list of objects that require to be expanded themselves.
23
- class AuthorWithExpandableCacheElements < Author
24
- # For the test purposes it's important that #to_s for HasCacheKey differs
25
- # between instances, hence not a Struct.
26
- class HasCacheKey
27
- attr_reader :cache_key
28
- def initialize(cache_key)
29
- @cache_key = cache_key
30
- end
31
-
32
- def to_s
33
- "HasCacheKey##{object_id}"
34
- end
35
- end
36
-
37
- def cache_key
38
- [
39
- HasCacheKey.new(name),
40
- HasCacheKey.new(id)
41
- ]
42
- end
43
- end
44
- class UncachedAuthor < Author
45
- # To confirm cache_key is set using updated_at and cache_key option passed to cache
46
- undef_method :cache_key
47
- end
48
- class AuthorSerializer < ActiveModel::Serializer
49
- cache key: 'writer', skip_digest: true
50
- attributes :id, :name
51
-
52
- has_many :posts
53
- has_many :roles
54
- has_one :bio
55
- end
56
-
57
- class Blog < ::Model
58
- attributes :name
59
- associations :writer
60
- end
61
- class BlogSerializer < ActiveModel::Serializer
62
- cache key: 'blog'
63
- attributes :id, :name
64
-
65
- belongs_to :writer
66
- end
67
-
68
- class Comment < ::Model
69
- attributes :id, :body
70
- associations :post, :author
71
-
72
- # Uses a custom non-time-based cache key
73
- def cache_key
74
- "comment/#{id}"
75
- end
76
- end
77
- class CommentSerializer < ActiveModel::Serializer
78
- cache expires_in: 1.day, skip_digest: true
79
- attributes :id, :body
80
- belongs_to :post
81
- belongs_to :author
82
- end
83
-
84
- class Post < ::Model
85
- attributes :id, :title, :body
86
- associations :author, :comments, :blog
87
- end
88
- class PostSerializer < ActiveModel::Serializer
89
- cache key: 'post', expires_in: 0.1, skip_digest: true
90
- attributes :id, :title, :body
91
-
92
- has_many :comments
93
- belongs_to :blog
94
- belongs_to :author
95
- end
96
-
97
- class Role < ::Model
98
- attributes :name, :description, :special_attribute
99
- associations :author
100
- end
101
- class RoleSerializer < ActiveModel::Serializer
102
- cache only: [:name, :slug], skip_digest: true
103
- attributes :id, :name, :description
104
- attribute :friendly_id, key: :slug
105
- belongs_to :author
106
-
107
- def friendly_id
108
- "#{object.name}-#{object.id}"
109
- end
110
- end
111
- class InheritedRoleSerializer < RoleSerializer
112
- cache key: 'inherited_role', only: [:name, :special_attribute]
113
- attribute :special_attribute
114
- end
115
-
116
- setup do
117
- cache_store.clear
118
- @comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
119
- @post = Post.new(id: 'post', title: 'New Post', body: 'Body')
120
- @bio = Bio.new(id: 1, content: 'AMS Contributor')
121
- @author = Author.new(id: 'author', name: 'Joao M. D. Moura')
122
- @blog = Blog.new(id: 999, name: 'Custom blog', writer: @author)
123
- @role = Role.new(name: 'Great Author')
124
- @location = Location.new(lat: '-23.550520', lng: '-46.633309')
125
- @place = Place.new(name: 'Amazing Place')
126
- @author.posts = [@post]
127
- @author.roles = [@role]
128
- @role.author = @author
129
- @author.bio = @bio
130
- @bio.author = @author
131
- @post.comments = [@comment]
132
- @post.author = @author
133
- @comment.post = @post
134
- @comment.author = @author
135
- @post.blog = @blog
136
- @location.place = @place
137
-
138
- @location_serializer = LocationSerializer.new(@location)
139
- @bio_serializer = BioSerializer.new(@bio)
140
- @role_serializer = RoleSerializer.new(@role)
141
- @post_serializer = PostSerializer.new(@post)
142
- @author_serializer = AuthorSerializer.new(@author)
143
- @comment_serializer = CommentSerializer.new(@comment)
144
- @blog_serializer = BlogSerializer.new(@blog)
145
- end
146
-
147
- def test_explicit_cache_store
148
- default_store = Class.new(ActiveModel::Serializer) do
149
- cache
150
- end
151
- explicit_store = Class.new(ActiveModel::Serializer) do
152
- cache cache_store: ActiveSupport::Cache::FileStore
153
- end
154
-
155
- assert ActiveSupport::Cache::MemoryStore, ActiveModelSerializers.config.cache_store
156
- assert ActiveSupport::Cache::MemoryStore, default_store.cache_store
157
- assert ActiveSupport::Cache::FileStore, explicit_store.cache_store
158
- end
159
-
160
- def test_inherited_cache_configuration
161
- inherited_serializer = Class.new(PostSerializer)
162
-
163
- assert_equal PostSerializer._cache_key, inherited_serializer._cache_key
164
- assert_equal PostSerializer._cache_options, inherited_serializer._cache_options
165
- end
166
-
167
- def test_override_cache_configuration
168
- inherited_serializer = Class.new(PostSerializer) do
169
- cache key: 'new-key'
170
- end
171
-
172
- assert_equal PostSerializer._cache_key, 'post'
173
- assert_equal inherited_serializer._cache_key, 'new-key'
174
- end
175
-
176
- def test_cache_definition
177
- assert_equal(cache_store, @post_serializer.class._cache)
178
- assert_equal(cache_store, @author_serializer.class._cache)
179
- assert_equal(cache_store, @comment_serializer.class._cache)
180
- end
181
-
182
- def test_cache_key_definition
183
- assert_equal('post', @post_serializer.class._cache_key)
184
- assert_equal('writer', @author_serializer.class._cache_key)
185
- assert_nil(@comment_serializer.class._cache_key)
186
- end
187
-
188
- def test_cache_key_interpolation_with_updated_at_when_cache_key_is_not_defined_on_object
189
- uncached_author = UncachedAuthor.new(name: 'Joao M. D. Moura')
190
- uncached_author_serializer = AuthorSerializer.new(uncached_author)
191
-
192
- render_object_with_cache(uncached_author)
193
- key = "#{uncached_author_serializer.class._cache_key}/#{uncached_author_serializer.object.id}-#{uncached_author_serializer.object.updated_at.strftime('%Y%m%d%H%M%S%9N')}"
194
- key = "#{key}/#{adapter.cache_key}"
195
- assert_equal(uncached_author_serializer.attributes.to_json, cache_store.fetch(key).to_json)
196
- end
197
-
198
- def test_cache_key_expansion
199
- author = AuthorWithExpandableCacheElements.new(id: 10, name: 'hello')
200
- same_author = AuthorWithExpandableCacheElements.new(id: 10, name: 'hello')
201
- diff_author = AuthorWithExpandableCacheElements.new(id: 11, name: 'hello')
202
-
203
- author_serializer = AuthorSerializer.new(author)
204
- same_author_serializer = AuthorSerializer.new(same_author)
205
- diff_author_serializer = AuthorSerializer.new(diff_author)
206
- adapter = AuthorSerializer.serialization_adapter_instance
207
-
208
- assert_equal(author_serializer.cache_key(adapter), same_author_serializer.cache_key(adapter))
209
- refute_equal(author_serializer.cache_key(adapter), diff_author_serializer.cache_key(adapter))
210
- end
211
-
212
- def test_default_cache_key_fallback
213
- render_object_with_cache(@comment)
214
- key = "#{@comment.cache_key}/#{adapter.cache_key}"
215
- assert_equal(@comment_serializer.attributes.to_json, cache_store.fetch(key).to_json)
216
- end
217
-
218
- def test_error_is_raised_if_cache_key_is_not_defined_on_object_or_passed_as_cache_option
219
- article = Article.new(title: 'Must Read')
220
- e = assert_raises ActiveModel::Serializer::UndefinedCacheKey do
221
- render_object_with_cache(article)
222
- end
223
- assert_match(/ActiveModelSerializers::CacheTest::Article must define #cache_key, or the 'key:' option must be passed into 'ActiveModelSerializers::CacheTest::ArticleSerializer.cache'/, e.message)
224
- end
225
-
226
- def test_cache_options_definition
227
- assert_equal({ expires_in: 0.1, skip_digest: true }, @post_serializer.class._cache_options)
228
- assert_nil(@blog_serializer.class._cache_options)
229
- assert_equal({ expires_in: 1.day, skip_digest: true }, @comment_serializer.class._cache_options)
230
- end
231
-
232
- def test_fragment_cache_definition
233
- assert_equal([:name, :slug], @role_serializer.class._cache_only)
234
- assert_equal([:content], @bio_serializer.class._cache_except)
235
- end
236
-
237
- def test_associations_separately_cache
238
- cache_store.clear
239
- assert_nil(cache_store.fetch(@post.cache_key))
240
- assert_nil(cache_store.fetch(@comment.cache_key))
241
-
242
- Timecop.freeze(Time.current) do
243
- render_object_with_cache(@post)
244
-
245
- key = "#{@post.cache_key}/#{adapter.cache_key}"
246
- assert_equal(@post_serializer.attributes, cache_store.fetch(key))
247
- key = "#{@comment.cache_key}/#{adapter.cache_key}"
248
- assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
249
- end
250
- end
251
-
252
- def test_associations_cache_when_updated
253
- Timecop.freeze(Time.current) do
254
- # Generate a new Cache of Post object and each objects related to it.
255
- render_object_with_cache(@post)
256
-
257
- # Check if it cached the objects separately
258
- key = "#{@post.cache_key}/#{adapter.cache_key}"
259
- assert_equal(@post_serializer.attributes, cache_store.fetch(key))
260
- key = "#{@comment.cache_key}/#{adapter.cache_key}"
261
- assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
262
-
263
- # Simulating update on comments relationship with Post
264
- new_comment = Comment.new(id: 2567, body: 'ZOMG A NEW COMMENT')
265
- new_comment_serializer = CommentSerializer.new(new_comment)
266
- @post.comments = [new_comment]
267
-
268
- # Ask for the serialized object
269
- render_object_with_cache(@post)
270
-
271
- # Check if the the new comment was cached
272
- key = "#{new_comment.cache_key}/#{adapter.cache_key}"
273
- assert_equal(new_comment_serializer.attributes, cache_store.fetch(key))
274
- key = "#{@post.cache_key}/#{adapter.cache_key}"
275
- assert_equal(@post_serializer.attributes, cache_store.fetch(key))
276
- end
277
- end
278
-
279
- def test_fragment_fetch_with_virtual_associations
280
- expected_result = {
281
- id: @location.id,
282
- lat: @location.lat,
283
- lng: @location.lng,
284
- address: 'Nowhere'
285
- }
286
-
287
- hash = render_object_with_cache(@location)
288
-
289
- assert_equal(hash, expected_result)
290
- key = "#{@location.cache_key}/#{adapter.cache_key}"
291
- assert_equal({ address: 'Nowhere' }, cache_store.fetch(key))
292
- end
293
-
294
- def test_fragment_cache_with_inheritance
295
- inherited = render_object_with_cache(@role, serializer: InheritedRoleSerializer)
296
- base = render_object_with_cache(@role)
297
-
298
- assert_includes(inherited.keys, :special_attribute)
299
- refute_includes(base.keys, :special_attribute)
300
- end
301
-
302
- def test_uses_adapter_in_cache_key
303
- render_object_with_cache(@post)
304
- key = "#{@post.cache_key}/#{adapter.class.to_s.demodulize.underscore}"
305
- assert_equal(@post_serializer.attributes, cache_store.fetch(key))
306
- end
307
-
308
- # Based on original failing test by @kevintyll
309
- # rubocop:disable Metrics/AbcSize
310
- def test_a_serializer_rendered_by_two_adapter_returns_differently_fetch_attributes
311
- Object.const_set(:Alert, Class.new(ActiveModelSerializers::Model) do
312
- attributes :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
313
- end)
314
- Object.const_set(:UncachedAlertSerializer, Class.new(ActiveModel::Serializer) do
315
- attributes :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
316
- end)
317
- Object.const_set(:AlertSerializer, Class.new(UncachedAlertSerializer) do
318
- cache
319
- end)
320
-
321
- alert = Alert.new(
322
- id: 1,
323
- status: 'fail',
324
- resource: 'resource-1',
325
- started_at: Time.new(2016, 3, 31, 21, 36, 35, 0),
326
- ended_at: nil,
327
- updated_at: Time.new(2016, 3, 31, 21, 27, 35, 0),
328
- created_at: Time.new(2016, 3, 31, 21, 37, 35, 0)
329
- )
330
-
331
- expected_fetch_attributes = {
332
- id: 1,
333
- status: 'fail',
334
- resource: 'resource-1',
335
- started_at: alert.started_at,
336
- ended_at: nil,
337
- updated_at: alert.updated_at,
338
- created_at: alert.created_at
339
- }.with_indifferent_access
340
- expected_cached_jsonapi_attributes = {
341
- id: '1',
342
- type: 'alerts',
343
- attributes: {
344
- status: 'fail',
345
- resource: 'resource-1',
346
- started_at: alert.started_at,
347
- ended_at: nil,
348
- updated_at: alert.updated_at,
349
- created_at: alert.created_at
350
- }
351
- }.with_indifferent_access
352
-
353
- # Assert attributes are serialized correctly
354
- serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :attributes)
355
- attributes_serialization = serializable_alert.as_json.with_indifferent_access
356
- assert_equal expected_fetch_attributes, alert.attributes
357
- assert_equal alert.attributes, attributes_serialization
358
- attributes_cache_key = serializable_alert.adapter.serializer.cache_key(serializable_alert.adapter)
359
- assert_equal attributes_serialization, cache_store.fetch(attributes_cache_key).with_indifferent_access
360
-
361
- serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :json_api)
362
- jsonapi_cache_key = serializable_alert.adapter.serializer.cache_key(serializable_alert.adapter)
363
- # Assert cache keys differ
364
- refute_equal attributes_cache_key, jsonapi_cache_key
365
- # Assert (cached) serializations differ
366
- jsonapi_serialization = serializable_alert.as_json
367
- assert_equal alert.status, jsonapi_serialization.fetch(:data).fetch(:attributes).fetch(:status)
368
- serializable_alert = serializable(alert, serializer: UncachedAlertSerializer, adapter: :json_api)
369
- assert_equal serializable_alert.as_json, jsonapi_serialization
370
-
371
- cached_serialization = cache_store.fetch(jsonapi_cache_key).with_indifferent_access
372
- assert_equal expected_cached_jsonapi_attributes, cached_serialization
373
- ensure
374
- Object.send(:remove_const, :Alert)
375
- Object.send(:remove_const, :AlertSerializer)
376
- Object.send(:remove_const, :UncachedAlertSerializer)
377
- end
378
- # rubocop:enable Metrics/AbcSize
379
-
380
- def test_uses_file_digest_in_cache_key
381
- render_object_with_cache(@blog)
382
- file_digest = Digest::MD5.hexdigest(File.open(__FILE__).read)
383
- key = "#{@blog.cache_key}/#{adapter.cache_key}/#{file_digest}"
384
- assert_equal(@blog_serializer.attributes, cache_store.fetch(key))
385
- end
386
-
387
- def test_cache_digest_definition
388
- file_digest = Digest::MD5.hexdigest(File.open(__FILE__).read)
389
- assert_equal(file_digest, @post_serializer.class._cache_digest)
390
- end
391
-
392
- def test_object_cache_keys
393
- serializable = ActiveModelSerializers::SerializableResource.new([@comment, @comment])
394
- include_directive = JSONAPI::IncludeDirective.new('*', allow_wildcard: true)
395
-
396
- actual = ActiveModel::Serializer.object_cache_keys(serializable.adapter.serializer, serializable.adapter, include_directive)
397
-
398
- assert_equal 3, actual.size
399
- expected_key = "comment/1/#{serializable.adapter.cache_key}"
400
- assert actual.any? { |key| key == expected_key }, "actual '#{actual}' should include #{expected_key}"
401
- expected_key = %r{post/post-\d+}
402
- assert actual.any? { |key| key =~ expected_key }, "actual '#{actual}' should match '#{expected_key}'"
403
- expected_key = %r{author/author-\d+}
404
- assert actual.any? { |key| key =~ expected_key }, "actual '#{actual}' should match '#{expected_key}'"
405
- end
406
-
407
- # rubocop:disable Metrics/AbcSize
408
- def test_fetch_attributes_from_cache
409
- serializers = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
410
-
411
- Timecop.freeze(Time.current) do
412
- render_object_with_cache(@comment)
413
-
414
- options = {}
415
- adapter_options = {}
416
- adapter_instance = ActiveModelSerializers::Adapter::Attributes.new(serializers, adapter_options)
417
- serializers.serializable_hash(adapter_options, options, adapter_instance)
418
- cached_attributes = adapter_options.fetch(:cached_attributes).with_indifferent_access
419
-
420
- include_directive = ActiveModelSerializers.default_include_directive
421
- manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive).with_indifferent_access
422
- assert_equal manual_cached_attributes, cached_attributes
423
-
424
- assert_equal cached_attributes["#{@comment.cache_key}/#{adapter_instance.cache_key}"], Comment.new(id: 1, body: 'ZOMG A COMMENT').attributes
425
- assert_equal cached_attributes["#{@comment.post.cache_key}/#{adapter_instance.cache_key}"], Post.new(id: 'post', title: 'New Post', body: 'Body').attributes
426
-
427
- writer = @comment.post.blog.writer
428
- writer_cache_key = writer.cache_key
429
- assert_equal cached_attributes["#{writer_cache_key}/#{adapter_instance.cache_key}"], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
430
- end
431
- end
432
- # rubocop:enable Metrics/AbcSize
433
-
434
- def test_cache_read_multi_with_fragment_cache_enabled
435
- post_serializer = Class.new(ActiveModel::Serializer) do
436
- cache except: [:body]
437
- end
438
-
439
- serializers = ActiveModel::Serializer::CollectionSerializer.new([@post, @post], serializer: post_serializer)
440
-
441
- Timecop.freeze(Time.current) do
442
- # Warming up.
443
- options = {}
444
- adapter_options = {}
445
- adapter_instance = ActiveModelSerializers::Adapter::Attributes.new(serializers, adapter_options)
446
- serializers.serializable_hash(adapter_options, options, adapter_instance)
447
-
448
- # Should find something with read_multi now
449
- adapter_options = {}
450
- serializers.serializable_hash(adapter_options, options, adapter_instance)
451
- cached_attributes = adapter_options.fetch(:cached_attributes)
452
-
453
- include_directive = ActiveModelSerializers.default_include_directive
454
- manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive)
455
-
456
- refute_equal 0, cached_attributes.size
457
- refute_equal 0, manual_cached_attributes.size
458
- assert_equal manual_cached_attributes, cached_attributes
459
- end
460
- end
461
-
462
- def test_serializer_file_path_on_nix
463
- path = '/Users/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
464
- caller_line = "#{path}:1:in `<top (required)>'"
465
- assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
466
- end
467
-
468
- def test_serializer_file_path_on_windows
469
- path = 'c:/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
470
- caller_line = "#{path}:1:in `<top (required)>'"
471
- assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
472
- end
473
-
474
- def test_serializer_file_path_with_space
475
- path = '/Users/git/ember js/ember-crm-backend/app/serializers/lead_serializer.rb'
476
- caller_line = "#{path}:1:in `<top (required)>'"
477
- assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
478
- end
479
-
480
- def test_serializer_file_path_with_submatch
481
- # The submatch in the path ensures we're using a correctly greedy regexp.
482
- path = '/Users/git/ember js/ember:123:in x/app/serializers/lead_serializer.rb'
483
- caller_line = "#{path}:1:in `<top (required)>'"
484
- assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
485
- end
486
-
487
- def test_digest_caller_file
488
- contents = "puts 'AMS rocks'!"
489
- dir = Dir.mktmpdir('space char')
490
- file = Tempfile.new('some_ruby.rb', dir)
491
- file.write(contents)
492
- path = file.path
493
- caller_line = "#{path}:1:in `<top (required)>'"
494
- file.close
495
- assert_equal ActiveModel::Serializer.digest_caller_file(caller_line), Digest::MD5.hexdigest(contents)
496
- ensure
497
- file.unlink
498
- FileUtils.remove_entry dir
499
- end
500
-
501
- def test_warn_on_serializer_not_defined_in_file
502
- called = false
503
- serializer = Class.new(ActiveModel::Serializer)
504
- assert_output(nil, /_cache_digest/) do
505
- serializer.digest_caller_file('')
506
- called = true
507
- end
508
- assert called
509
- end
510
-
511
- def test_cached_false_without_cache_store
512
- cached_serializer = build_cached_serializer do |serializer|
513
- serializer._cache = nil
514
- end
515
- refute cached_serializer.class.cache_enabled?
516
- end
517
-
518
- def test_cached_true_with_cache_store_and_without_cache_only_and_cache_except
519
- cached_serializer = build_cached_serializer do |serializer|
520
- serializer._cache = Object
521
- end
522
- assert cached_serializer.class.cache_enabled?
523
- end
524
-
525
- def test_cached_false_with_cache_store_and_with_cache_only
526
- cached_serializer = build_cached_serializer do |serializer|
527
- serializer._cache = Object
528
- serializer._cache_only = [:name]
529
- end
530
- refute cached_serializer.class.cache_enabled?
531
- end
532
-
533
- def test_cached_false_with_cache_store_and_with_cache_except
534
- cached_serializer = build_cached_serializer do |serializer|
535
- serializer._cache = Object
536
- serializer._cache_except = [:content]
537
- end
538
- refute cached_serializer.class.cache_enabled?
539
- end
540
-
541
- def test_fragment_cached_false_without_cache_store
542
- cached_serializer = build_cached_serializer do |serializer|
543
- serializer._cache = nil
544
- serializer._cache_only = [:name]
545
- end
546
- refute cached_serializer.class.fragment_cache_enabled?
547
- end
548
-
549
- def test_fragment_cached_true_with_cache_store_and_cache_only
550
- cached_serializer = build_cached_serializer do |serializer|
551
- serializer._cache = Object
552
- serializer._cache_only = [:name]
553
- end
554
- assert cached_serializer.class.fragment_cache_enabled?
555
- end
556
-
557
- def test_fragment_cached_true_with_cache_store_and_cache_except
558
- cached_serializer = build_cached_serializer do |serializer|
559
- serializer._cache = Object
560
- serializer._cache_except = [:content]
561
- end
562
- assert cached_serializer.class.fragment_cache_enabled?
563
- end
564
-
565
- def test_fragment_cached_false_with_cache_store_and_cache_except_and_cache_only
566
- cached_serializer = build_cached_serializer do |serializer|
567
- serializer._cache = Object
568
- serializer._cache_except = [:content]
569
- serializer._cache_only = [:name]
570
- end
571
- refute cached_serializer.class.fragment_cache_enabled?
572
- end
573
-
574
- def test_fragment_fetch_with_virtual_attributes
575
- author = Author.new(name: 'Joao M. D. Moura')
576
- role = Role.new(name: 'Great Author', description: nil)
577
- role.author = [author]
578
- role_serializer = RoleSerializer.new(role)
579
- adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(role_serializer)
580
- expected_result = {
581
- id: role.id,
582
- description: role.description,
583
- slug: "#{role.name}-#{role.id}",
584
- name: role.name
585
- }
586
- cache_store.clear
587
-
588
- role_hash = role_serializer.fetch_attributes_fragment(adapter_instance)
589
- assert_equal(role_hash, expected_result)
590
-
591
- role.id = 'this has been updated'
592
- role.name = 'this was cached'
593
-
594
- role_hash = role_serializer.fetch_attributes_fragment(adapter_instance)
595
- assert_equal(expected_result.merge(id: role.id), role_hash)
596
- end
597
-
598
- def test_fragment_fetch_with_except
599
- adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(@bio_serializer)
600
- expected_result = {
601
- id: @bio.id,
602
- rating: nil,
603
- content: @bio.content
604
- }
605
- cache_store.clear
606
-
607
- bio_hash = @bio_serializer.fetch_attributes_fragment(adapter_instance)
608
- assert_equal(expected_result, bio_hash)
609
-
610
- @bio.content = 'this has been updated'
611
- @bio.rating = 'this was cached'
612
-
613
- bio_hash = @bio_serializer.fetch_attributes_fragment(adapter_instance)
614
- assert_equal(expected_result.merge(content: @bio.content), bio_hash)
615
- end
616
-
617
- def test_fragment_fetch_with_namespaced_object
618
- @spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
619
- @spam_serializer = Spam::UnrelatedLinkSerializer.new(@spam)
620
- adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(@spam_serializer)
621
- @spam_hash = @spam_serializer.fetch_attributes_fragment(adapter_instance)
622
- expected_result = {
623
- id: @spam.id
624
- }
625
- assert_equal(@spam_hash, expected_result)
626
- end
627
-
628
- private
629
-
630
- def cache_store
631
- ActiveModelSerializers.config.cache_store
632
- end
633
-
634
- def build_cached_serializer
635
- serializer = Class.new(ActiveModel::Serializer)
636
- serializer._cache_key = nil
637
- serializer._cache_options = nil
638
- yield serializer if block_given?
639
- serializer.new(Object)
640
- end
641
-
642
- def render_object_with_cache(obj, options = {})
643
- @serializable_resource = serializable(obj, options)
644
- @serializable_resource.serializable_hash
645
- end
646
-
647
- def adapter
648
- @serializable_resource.adapter
649
- end
650
- end
651
- end