active_model_serializers 0.10.0 → 0.10.7

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 (171) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +6 -5
  3. data/.travis.yml +30 -21
  4. data/CHANGELOG.md +172 -2
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +23 -4
  7. data/README.md +166 -28
  8. data/Rakefile +3 -32
  9. data/active_model_serializers.gemspec +22 -25
  10. data/appveyor.yml +10 -6
  11. data/bin/rubocop +38 -0
  12. data/docs/README.md +2 -1
  13. data/docs/general/adapters.md +35 -11
  14. data/docs/general/caching.md +7 -1
  15. data/docs/general/configuration_options.md +86 -1
  16. data/docs/general/deserialization.md +1 -1
  17. data/docs/general/fields.md +31 -0
  18. data/docs/general/getting_started.md +1 -1
  19. data/docs/general/logging.md +7 -0
  20. data/docs/general/rendering.md +63 -25
  21. data/docs/general/serializers.md +125 -14
  22. data/docs/howto/add_pagination_links.md +16 -17
  23. data/docs/howto/add_relationship_links.md +140 -0
  24. data/docs/howto/add_root_key.md +11 -0
  25. data/docs/howto/grape_integration.md +42 -0
  26. data/docs/howto/outside_controller_use.md +12 -4
  27. data/docs/howto/passing_arbitrary_options.md +2 -2
  28. data/docs/howto/serialize_poro.md +46 -5
  29. data/docs/howto/test.md +2 -0
  30. data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
  31. data/docs/integrations/ember-and-json-api.md +67 -32
  32. data/docs/jsonapi/schema.md +1 -1
  33. data/lib/action_controller/serialization.rb +13 -3
  34. data/lib/active_model/serializer/adapter/base.rb +2 -0
  35. data/lib/active_model/serializer/array_serializer.rb +8 -5
  36. data/lib/active_model/serializer/association.rb +62 -10
  37. data/lib/active_model/serializer/belongs_to_reflection.rb +4 -3
  38. data/lib/active_model/serializer/collection_serializer.rb +39 -13
  39. data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +82 -115
  40. data/lib/active_model/serializer/error_serializer.rb +11 -7
  41. data/lib/active_model/serializer/errors_serializer.rb +25 -20
  42. data/lib/active_model/serializer/has_many_reflection.rb +3 -3
  43. data/lib/active_model/serializer/has_one_reflection.rb +1 -4
  44. data/lib/active_model/serializer/lazy_association.rb +95 -0
  45. data/lib/active_model/serializer/lint.rb +134 -130
  46. data/lib/active_model/serializer/reflection.rb +127 -67
  47. data/lib/active_model/serializer/version.rb +1 -1
  48. data/lib/active_model/serializer.rb +297 -79
  49. data/lib/active_model_serializers/adapter/attributes.rb +3 -66
  50. data/lib/active_model_serializers/adapter/base.rb +39 -39
  51. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +2 -2
  52. data/lib/active_model_serializers/adapter/json_api/link.rb +1 -1
  53. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +47 -21
  54. data/lib/active_model_serializers/adapter/json_api/relationship.rb +75 -23
  55. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +39 -10
  56. data/lib/active_model_serializers/adapter/json_api.rb +71 -57
  57. data/lib/active_model_serializers/adapter.rb +6 -0
  58. data/lib/active_model_serializers/deprecate.rb +1 -2
  59. data/lib/active_model_serializers/deserialization.rb +2 -0
  60. data/lib/active_model_serializers/lookup_chain.rb +80 -0
  61. data/lib/active_model_serializers/model.rb +109 -28
  62. data/lib/active_model_serializers/railtie.rb +3 -1
  63. data/lib/active_model_serializers/register_jsonapi_renderer.rb +44 -31
  64. data/lib/active_model_serializers/serializable_resource.rb +6 -5
  65. data/lib/active_model_serializers/serialization_context.rb +10 -3
  66. data/lib/active_model_serializers/test/schema.rb +2 -2
  67. data/lib/active_model_serializers.rb +16 -1
  68. data/lib/generators/rails/resource_override.rb +1 -1
  69. data/lib/generators/rails/serializer_generator.rb +4 -4
  70. data/lib/grape/active_model_serializers.rb +7 -5
  71. data/lib/grape/formatters/active_model_serializers.rb +19 -2
  72. data/lib/grape/helpers/active_model_serializers.rb +1 -0
  73. data/lib/tasks/rubocop.rake +53 -0
  74. data/test/action_controller/adapter_selector_test.rb +14 -5
  75. data/test/action_controller/explicit_serializer_test.rb +5 -4
  76. data/test/action_controller/json/include_test.rb +106 -27
  77. data/test/action_controller/json_api/deserialization_test.rb +1 -1
  78. data/test/action_controller/json_api/errors_test.rb +8 -9
  79. data/test/action_controller/json_api/fields_test.rb +66 -0
  80. data/test/action_controller/json_api/linked_test.rb +29 -24
  81. data/test/action_controller/json_api/pagination_test.rb +31 -23
  82. data/test/action_controller/json_api/transform_test.rb +11 -3
  83. data/test/action_controller/lookup_proc_test.rb +49 -0
  84. data/test/action_controller/namespace_lookup_test.rb +232 -0
  85. data/test/action_controller/serialization_scope_name_test.rb +12 -6
  86. data/test/action_controller/serialization_test.rb +12 -9
  87. data/test/active_model_serializers/json_pointer_test.rb +15 -13
  88. data/test/active_model_serializers/model_test.rb +137 -4
  89. data/test/active_model_serializers/railtie_test_isolated.rb +12 -7
  90. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +161 -0
  91. data/test/active_model_serializers/serialization_context_test_isolated.rb +23 -10
  92. data/test/active_model_serializers/test/schema_test.rb +3 -2
  93. data/test/adapter/attributes_test.rb +40 -0
  94. data/test/adapter/json/collection_test.rb +14 -0
  95. data/test/adapter/json/has_many_test.rb +10 -2
  96. data/test/adapter/json/transform_test.rb +15 -15
  97. data/test/adapter/json_api/collection_test.rb +4 -3
  98. data/test/adapter/json_api/errors_test.rb +17 -19
  99. data/test/adapter/json_api/fields_test.rb +12 -3
  100. data/test/adapter/json_api/has_many_test.rb +49 -20
  101. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +213 -0
  102. data/test/adapter/json_api/json_api_test.rb +5 -7
  103. data/test/adapter/json_api/linked_test.rb +33 -12
  104. data/test/adapter/json_api/links_test.rb +4 -2
  105. data/test/adapter/json_api/pagination_links_test.rb +53 -13
  106. data/test/adapter/json_api/parse_test.rb +1 -1
  107. data/test/adapter/json_api/relationship_test.rb +309 -73
  108. data/test/adapter/json_api/resource_meta_test.rb +3 -3
  109. data/test/adapter/json_api/transform_test.rb +263 -253
  110. data/test/adapter/json_api/type_test.rb +168 -36
  111. data/test/adapter/json_test.rb +8 -7
  112. data/test/adapter/null_test.rb +1 -2
  113. data/test/adapter/polymorphic_test.rb +52 -5
  114. data/test/adapter_test.rb +1 -1
  115. data/test/benchmark/app.rb +1 -1
  116. data/test/benchmark/benchmarking_support.rb +1 -1
  117. data/test/benchmark/bm_active_record.rb +81 -0
  118. data/test/benchmark/bm_adapter.rb +38 -0
  119. data/test/benchmark/bm_caching.rb +16 -16
  120. data/test/benchmark/bm_lookup_chain.rb +83 -0
  121. data/test/benchmark/bm_transform.rb +21 -10
  122. data/test/benchmark/controllers.rb +16 -17
  123. data/test/benchmark/fixtures.rb +72 -72
  124. data/test/cache_test.rb +235 -69
  125. data/test/collection_serializer_test.rb +31 -14
  126. data/test/fixtures/active_record.rb +45 -10
  127. data/test/fixtures/poro.rb +124 -181
  128. data/test/generators/serializer_generator_test.rb +23 -5
  129. data/test/grape_test.rb +170 -56
  130. data/test/lint_test.rb +1 -1
  131. data/test/logger_test.rb +13 -11
  132. data/test/serializable_resource_test.rb +18 -22
  133. data/test/serializers/association_macros_test.rb +3 -2
  134. data/test/serializers/associations_test.rb +222 -49
  135. data/test/serializers/attribute_test.rb +5 -3
  136. data/test/serializers/attributes_test.rb +1 -1
  137. data/test/serializers/caching_configuration_test_isolated.rb +6 -6
  138. data/test/serializers/fieldset_test.rb +1 -1
  139. data/test/serializers/meta_test.rb +12 -6
  140. data/test/serializers/options_test.rb +17 -6
  141. data/test/serializers/read_attribute_for_serialization_test.rb +3 -3
  142. data/test/serializers/reflection_test.rb +427 -0
  143. data/test/serializers/root_test.rb +1 -1
  144. data/test/serializers/serialization_test.rb +2 -2
  145. data/test/serializers/serializer_for_test.rb +12 -10
  146. data/test/serializers/serializer_for_with_namespace_test.rb +88 -0
  147. data/test/support/isolated_unit.rb +9 -4
  148. data/test/support/rails5_shims.rb +8 -2
  149. data/test/support/rails_app.rb +2 -9
  150. data/test/support/serialization_testing.rb +31 -5
  151. data/test/test_helper.rb +13 -0
  152. metadata +130 -71
  153. data/.rubocop_todo.yml +0 -167
  154. data/docs/ARCHITECTURE.md +0 -126
  155. data/lib/active_model/serializer/associations.rb +0 -100
  156. data/lib/active_model/serializer/attributes.rb +0 -82
  157. data/lib/active_model/serializer/collection_reflection.rb +0 -7
  158. data/lib/active_model/serializer/configuration.rb +0 -35
  159. data/lib/active_model/serializer/include_tree.rb +0 -111
  160. data/lib/active_model/serializer/links.rb +0 -35
  161. data/lib/active_model/serializer/meta.rb +0 -29
  162. data/lib/active_model/serializer/singular_reflection.rb +0 -7
  163. data/lib/active_model/serializer/type.rb +0 -25
  164. data/lib/active_model_serializers/key_transform.rb +0 -70
  165. data/test/active_model_serializers/key_transform_test.rb +0 -263
  166. data/test/adapter/json_api/has_many_embed_ids_test.rb +0 -43
  167. data/test/adapter/json_api/relationships_test.rb +0 -199
  168. data/test/adapter/json_api/resource_identifier_test.rb +0 -85
  169. data/test/include_tree/from_include_args_test.rb +0 -26
  170. data/test/include_tree/from_string_test.rb +0 -94
  171. data/test/include_tree/include_args_to_hash_test.rb +0 -64
@@ -1,60 +1,192 @@
1
1
  require 'test_helper'
2
2
 
3
- module ActiveModel
4
- class Serializer
5
- module Adapter
6
- class JsonApi
7
- class TypeTest < ActiveSupport::TestCase
8
- class StringTypeSerializer < ActiveModel::Serializer
9
- attribute :name
10
- type 'profile'
3
+ module ActiveModelSerializers
4
+ module Adapter
5
+ class JsonApi
6
+ class TypeTest < ActiveSupport::TestCase
7
+ class StringTypeSerializer < ActiveModel::Serializer
8
+ attribute :name
9
+ type 'profile'
10
+ end
11
+
12
+ class SymbolTypeSerializer < ActiveModel::Serializer
13
+ attribute :name
14
+ type :profile
15
+ end
16
+
17
+ setup do
18
+ @author = Author.new(id: 1, name: 'Steve K.')
19
+ end
20
+
21
+ def test_config_plural
22
+ with_jsonapi_inflection :plural do
23
+ assert_type(@author, 'authors')
11
24
  end
25
+ end
12
26
 
13
- class SymbolTypeSerializer < ActiveModel::Serializer
14
- attribute :name
15
- type :profile
27
+ def test_config_singular
28
+ with_jsonapi_inflection :singular do
29
+ assert_type(@author, 'author')
16
30
  end
31
+ end
32
+
33
+ def test_explicit_string_type_value
34
+ assert_type(@author, 'profile', serializer: StringTypeSerializer)
35
+ end
36
+
37
+ def test_explicit_symbol_type_value
38
+ assert_type(@author, 'profile', serializer: SymbolTypeSerializer)
39
+ end
40
+
41
+ private
17
42
 
18
- setup do
19
- @author = Author.new(id: 1, name: 'Steve K.')
43
+ def assert_type(resource, expected_type, opts = {})
44
+ opts = opts.reverse_merge(adapter: :json_api)
45
+ hash = serializable(resource, opts).serializable_hash
46
+ assert_equal(expected_type, hash.fetch(:data).fetch(:type))
47
+ end
48
+ end
49
+ class ResourceIdentifierTest < ActiveSupport::TestCase
50
+ class WithDefinedTypeSerializer < ActiveModel::Serializer
51
+ type 'with_defined_types'
52
+ end
53
+
54
+ class WithDefinedIdSerializer < ActiveModel::Serializer
55
+ def id
56
+ 'special_id'
20
57
  end
58
+ end
59
+
60
+ class FragmentedSerializer < ActiveModel::Serializer
61
+ cache only: :id
21
62
 
22
- def test_config_plural
23
- with_jsonapi_resource_type :plural do
24
- assert_type(@author, 'authors')
25
- end
63
+ def id
64
+ 'special_id'
26
65
  end
66
+ end
67
+
68
+ setup do
69
+ @model = Author.new(id: 1, name: 'Steve K.')
70
+ ActionController::Base.cache_store.clear
71
+ end
27
72
 
28
- def test_config_singular
29
- with_jsonapi_resource_type :singular do
30
- assert_type(@author, 'author')
31
- end
73
+ def test_defined_type
74
+ actual = with_jsonapi_inflection :plural do
75
+ actual_resource_identifier_object(WithDefinedTypeSerializer, @model)
32
76
  end
77
+ expected = { id: expected_model_id(@model), type: 'with-defined-types' }
78
+ assert_equal actual, expected
79
+ end
33
80
 
34
- def test_explicit_string_type_value
35
- assert_type(@author, 'profile', serializer: StringTypeSerializer)
81
+ def test_defined_type_not_inflected
82
+ actual = with_jsonapi_inflection :singular do
83
+ actual_resource_identifier_object(WithDefinedTypeSerializer, @model)
36
84
  end
85
+ expected = { id: expected_model_id(@model), type: 'with-defined-types' }
86
+ assert_equal actual, expected
87
+ end
37
88
 
38
- def test_explicit_symbol_type_value
39
- assert_type(@author, 'profile', serializer: SymbolTypeSerializer)
89
+ def test_singular_type
90
+ actual = with_jsonapi_inflection :singular do
91
+ actual_resource_identifier_object(AuthorSerializer, @model)
40
92
  end
93
+ expected = { id: expected_model_id(@model), type: 'author' }
94
+ assert_equal actual, expected
95
+ end
41
96
 
42
- private
97
+ def test_plural_type
98
+ actual = with_jsonapi_inflection :plural do
99
+ actual_resource_identifier_object(AuthorSerializer, @model)
100
+ end
101
+ expected = { id: expected_model_id(@model), type: 'authors' }
102
+ assert_equal actual, expected
103
+ end
104
+
105
+ def test_type_with_namespace
106
+ Object.const_set(:Admin, Module.new)
107
+ model = Class.new(::Model)
108
+ Admin.const_set(:PowerUser, model)
109
+ serializer = Class.new(ActiveModel::Serializer)
110
+ Admin.const_set(:PowerUserSerializer, serializer)
111
+ with_namespace_separator '--' do
112
+ admin_user = Admin::PowerUser.new
113
+ serializer = Admin::PowerUserSerializer.new(admin_user)
114
+ expected = {
115
+ id: admin_user.id,
116
+ type: 'admin--power-users'
117
+ }
118
+
119
+ identifier = ResourceIdentifier.new(serializer, {})
120
+ actual = identifier.as_json
121
+ assert_equal(expected, actual)
122
+ end
123
+ end
124
+
125
+ def test_id_defined_on_object
126
+ actual = actual_resource_identifier_object(AuthorSerializer, @model)
127
+ expected = { id: @model.id.to_s, type: expected_model_type(@model) }
128
+ assert_equal actual, expected
129
+ end
130
+
131
+ def test_blank_id
132
+ model = Author.new(id: nil, name: 'Steve K.')
133
+ actual = actual_resource_identifier_object(AuthorSerializer, model)
134
+ expected = { type: expected_model_type(model) }
135
+ assert_equal actual, expected
136
+ end
137
+
138
+ def test_for_type_with_id
139
+ id = 1
140
+ actual = ResourceIdentifier.for_type_with_id('admin_user', id, {})
141
+ expected = { id: '1', type: 'admin-users' }
142
+ assert_equal actual, expected
143
+ end
43
144
 
44
- def assert_type(resource, expected_type, opts = {})
45
- opts = opts.reverse_merge(adapter: :json_api)
46
- hash = serializable(resource, opts).serializable_hash
47
- assert_equal(expected_type, hash.fetch(:data).fetch(:type))
145
+ def test_for_type_with_id_given_blank_id
146
+ id = ''
147
+ actual = ResourceIdentifier.for_type_with_id('admin_user', id, {})
148
+ expected = { type: 'admin-users' }
149
+ assert_equal actual, expected
150
+ end
151
+
152
+ def test_for_type_with_id_inflected
153
+ id = 2
154
+ actual = with_jsonapi_inflection :singular do
155
+ ResourceIdentifier.for_type_with_id('admin_users', id, {})
48
156
  end
157
+ expected = { id: '2', type: 'admin-user' }
158
+ assert_equal actual, expected
159
+ end
160
+
161
+ def test_id_defined_on_serializer
162
+ actual = actual_resource_identifier_object(WithDefinedIdSerializer, @model)
163
+ expected = { id: 'special_id', type: expected_model_type(@model) }
164
+ assert_equal actual, expected
165
+ end
166
+
167
+ def test_id_defined_on_fragmented
168
+ actual = actual_resource_identifier_object(FragmentedSerializer, @model)
169
+ expected = { id: 'special_id', type: expected_model_type(@model) }
170
+ assert_equal actual, expected
171
+ end
172
+
173
+ private
174
+
175
+ def actual_resource_identifier_object(serializer_class, model)
176
+ serializer = serializer_class.new(model)
177
+ resource_identifier = ResourceIdentifier.new(serializer, nil)
178
+ resource_identifier.as_json
179
+ end
49
180
 
50
- def with_jsonapi_resource_type inflection
51
- old_inflection = ActiveModelSerializers.config.jsonapi_resource_type
52
- ActiveModelSerializers.config.jsonapi_resource_type = inflection
53
- yield
54
- ensure
55
- ActiveModelSerializers.config.jsonapi_resource_type = old_inflection
181
+ def expected_model_type(model, inflection = ActiveModelSerializers.config.jsonapi_resource_type)
182
+ with_jsonapi_inflection inflection do
183
+ model.class.model_name.send(inflection)
56
184
  end
57
185
  end
186
+
187
+ def expected_model_id(model)
188
+ model.id.to_s
189
+ end
58
190
  end
59
191
  end
60
192
  end
@@ -32,13 +32,14 @@ module ActiveModelSerializers
32
32
  adapter = ActiveModelSerializers::Adapter::Json.new(serializer)
33
33
 
34
34
  assert_equal({
35
- id: 1,
36
- reviews: [{ id: 1, body: 'ZOMG A COMMENT' },
37
- { id: 2, body: 'ZOMG ANOTHER COMMENT' }
38
- ],
39
- writer: { id: 1, name: 'Steve K.' },
40
- site: { id: 1, name: 'My Blog!!' }
41
- }, adapter.serializable_hash[:post])
35
+ id: 1,
36
+ reviews: [
37
+ { id: 1, body: 'ZOMG A COMMENT' },
38
+ { id: 2, body: 'ZOMG ANOTHER COMMENT' }
39
+ ],
40
+ writer: { id: 1, name: 'Steve K.' },
41
+ site: { id: 1, name: 'My Blog!!' }
42
+ }, adapter.serializable_hash[:post])
42
43
  end
43
44
  end
44
45
  end
@@ -4,7 +4,7 @@ module ActiveModelSerializers
4
4
  module Adapter
5
5
  class NullTest < ActiveSupport::TestCase
6
6
  def setup
7
- profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
7
+ profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
8
8
  serializer = ProfileSerializer.new(profile)
9
9
 
10
10
  @adapter = Null.new(serializer)
@@ -20,4 +20,3 @@ module ActiveModelSerializers
20
20
  end
21
21
  end
22
22
  end
23
-
@@ -27,11 +27,11 @@ module ActiveModel
27
27
  id: 1,
28
28
  title: 'headshot-1.jpg',
29
29
  imageable: {
30
- type: 'employee',
31
- employee: {
32
- id: 42,
33
- name: 'Zoop Zoopler'
34
- }
30
+ type: 'employee',
31
+ employee: {
32
+ id: 42,
33
+ name: 'Zoop Zoopler'
34
+ }
35
35
  }
36
36
  }
37
37
 
@@ -165,6 +165,53 @@ module ActiveModel
165
165
 
166
166
  assert_equal(expected, serialization(@picture, :json_api))
167
167
  end
168
+
169
+ def test_json_api_serialization_with_polymorphic_belongs_to
170
+ expected = {
171
+ data: {
172
+ id: '1',
173
+ type: 'poly-tags',
174
+ attributes: { phrase: 'foo' },
175
+ relationships: {
176
+ :"object-tags" => {
177
+ data: [
178
+ { id: '1', type: 'object-tags' },
179
+ { id: '5', type: 'object-tags' }
180
+ ]
181
+ }
182
+ }
183
+ },
184
+ included: [
185
+ {
186
+ id: '1',
187
+ type: 'object-tags',
188
+ relationships: {
189
+ taggable: {
190
+ data: { id: '42', type: 'employees' }
191
+ }
192
+ }
193
+ },
194
+ {
195
+ id: '42',
196
+ type: 'employees'
197
+ },
198
+ {
199
+ id: '5',
200
+ type: 'object-tags',
201
+ relationships: {
202
+ taggable: {
203
+ data: { id: '1', type: 'pictures' }
204
+ }
205
+ }
206
+ },
207
+ {
208
+ id: '1',
209
+ type: 'pictures'
210
+ }
211
+ ]
212
+ }
213
+ assert_equal(expected, tag_serialization(:json_api))
214
+ end
168
215
  end
169
216
  end
170
217
  end
data/test/adapter_test.rb CHANGED
@@ -51,7 +51,7 @@ module ActiveModelSerializers
51
51
  end
52
52
 
53
53
  def test_create_adapter_with_override
54
- adapter = ActiveModelSerializers::Adapter.create(@serializer, { adapter: :json_api })
54
+ adapter = ActiveModelSerializers::Adapter.create(@serializer, adapter: :json_api)
55
55
  assert_equal ActiveModelSerializers::Adapter::JsonApi, adapter.class
56
56
  end
57
57
 
@@ -43,7 +43,7 @@ class BenchmarkApp < Rails::Application
43
43
  config.secret_key_base = 'abc123'
44
44
  config.consider_all_requests_local = false
45
45
 
46
- # otherwise deadlock occured
46
+ # otherwise deadlock occurred
47
47
  config.middleware.delete 'Rack::Lock'
48
48
 
49
49
  # to disable log files
@@ -36,7 +36,7 @@ module Benchmark
36
36
  version: ::ActiveModel::Serializer::VERSION.to_s,
37
37
  rails_version: ::Rails.version.to_s,
38
38
  iterations_per_second: entry.ips,
39
- iterations_per_second_standard_deviation: entry.stddev_percentage,
39
+ iterations_per_second_standard_deviation: entry.error_percentage,
40
40
  total_allocated_objects_per_iteration: count_total_allocated_objects(&block)
41
41
  }.to_json
42
42
 
@@ -0,0 +1,81 @@
1
+ require_relative './benchmarking_support'
2
+ require_relative './app'
3
+
4
+ time = 10
5
+ disable_gc = true
6
+
7
+ # This is to disable any key transform effects that may impact performance
8
+ ActiveModelSerializers.config.key_transform = :unaltered
9
+
10
+ ###########################################
11
+ # Setup active record models
12
+ ##########################################
13
+ require 'active_record'
14
+ require 'sqlite3'
15
+
16
+ # For debugging SQL output
17
+ # ActiveRecord::Base.logger = Logger.new(STDERR)
18
+
19
+ # Change the following to reflect your database settings
20
+ ActiveRecord::Base.establish_connection(
21
+ adapter: 'sqlite3',
22
+ database: ':memory:'
23
+ )
24
+
25
+ # Don't show migration output when constructing fake db
26
+ ActiveRecord::Migration.verbose = false
27
+
28
+ ActiveRecord::Schema.define do
29
+ create_table :authors, force: true do |t|
30
+ t.string :name
31
+ end
32
+
33
+ create_table :posts, force: true do |t|
34
+ t.text :body
35
+ t.string :title
36
+ t.references :author
37
+ end
38
+
39
+ create_table :profiles, force: true do |t|
40
+ t.text :project_url
41
+ t.text :bio
42
+ t.date :birthday
43
+ t.references :author
44
+ end
45
+ end
46
+
47
+ class Author < ActiveRecord::Base
48
+ has_one :profile
49
+ has_many :posts
50
+ end
51
+
52
+ class Post < ActiveRecord::Base
53
+ belongs_to :author
54
+ end
55
+
56
+ class Profile < ActiveRecord::Base
57
+ belongs_to :author
58
+ end
59
+
60
+ # Build out the data to serialize
61
+ author = Author.create(name: 'Preston Sego')
62
+ Profile.create(project_url: 'https://github.com/NullVoxPopuli', author: author)
63
+ 50.times do
64
+ Post.create(
65
+ body: 'something about how password restrictions are evil, and less secure, and with the math to prove it.',
66
+ title: 'Your bank is does not know how to do security',
67
+ author: author
68
+ )
69
+ end
70
+
71
+ Benchmark.ams('AR: attributes', time: time, disable_gc: disable_gc) do
72
+ ActiveModelSerializers::SerializableResource.new(author, adapter: :attributes, include: 'profile,posts').serializable_hash
73
+ end
74
+
75
+ Benchmark.ams('AR: json', time: time, disable_gc: disable_gc) do
76
+ ActiveModelSerializers::SerializableResource.new(author, adapter: :json, include: 'profile,posts').serializable_hash
77
+ end
78
+
79
+ Benchmark.ams('AR: JSON API', time: time, disable_gc: disable_gc) do
80
+ ActiveModelSerializers::SerializableResource.new(author, adapter: :json_api, include: 'profile,posts').serializable_hash
81
+ end
@@ -0,0 +1,38 @@
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..60).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
+
25
+ Benchmark.ams('attributes', time: time, disable_gc: disable_gc) do
26
+ attributes = ActiveModelSerializers::Adapter::Attributes.new(serializer)
27
+ attributes.as_json
28
+ end
29
+
30
+ Benchmark.ams('json_api', time: time, disable_gc: disable_gc) do
31
+ json_api = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
32
+ json_api.as_json
33
+ end
34
+
35
+ Benchmark.ams('json', time: time, disable_gc: disable_gc) do
36
+ json = ActiveModelSerializers::Adapter::Json.new(serializer)
37
+ json.as_json
38
+ end
@@ -4,7 +4,7 @@ require_relative './app'
4
4
  # https://github.com/ruby-bench/ruby-bench-suite/blob/8ad567f7e43a044ae48c36833218423bb1e2bd9d/rails/benchmarks/actionpack_router.rb
5
5
  class ApiAssertion
6
6
  include Benchmark::ActiveModelSerializers::TestMethods
7
- BadRevisionError = Class.new(StandardError)
7
+ class BadRevisionError < StandardError; end
8
8
 
9
9
  def valid?
10
10
  caching = get_caching
@@ -66,27 +66,27 @@ class ApiAssertion
66
66
  def expected
67
67
  @expected ||=
68
68
  {
69
- 'post' => {
70
- 'id' => 1337,
71
- 'title' => 'New Post',
69
+ 'primary_resource' => {
70
+ 'id' => 1337,
71
+ 'title' => 'New PrimaryResource',
72
72
  'body' => 'Body',
73
- 'comments' => [
74
- {
75
- 'id' => 1,
76
- 'body' => 'ZOMG A COMMENT'
77
- }
78
- ],
79
- 'blog' => {
80
- 'id' => 999,
81
- 'name' => 'Custom blog'
73
+ 'virtual_attribute' => {
74
+ 'id' => 999,
75
+ 'name' => 'Free-Range Virtual Attribute'
82
76
  },
83
- 'author' => {
77
+ 'has_one_relationship' => {
84
78
  'id' => 42,
85
79
  'first_name' => 'Joao',
86
80
  'last_name' => 'Moura'
87
- }
81
+ },
82
+ 'has_many_relationships' => [
83
+ {
84
+ 'id' => 1,
85
+ 'body' => 'ZOMG A HAS MANY RELATIONSHIP'
86
+ }
87
+ ]
88
88
  }
89
- }
89
+ }
90
90
  end
91
91
 
92
92
  def assert_equal(expected, actual, message)
@@ -0,0 +1,83 @@
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
@@ -4,31 +4,42 @@ require_relative './app'
4
4
  time = 10
5
5
  disable_gc = true
6
6
  ActiveModelSerializers.config.key_transform = :unaltered
7
- comments = (0..50).map do |i|
8
- Comment.new(id: i, body: 'ZOMG A COMMENT')
7
+ has_many_relationships = (0..50).map do |i|
8
+ HasManyRelationship.new(id: i, body: 'ZOMG A HAS MANY RELATIONSHIP')
9
9
  end
10
- author = Author.new(id: 42, first_name: 'Joao', last_name: 'Moura')
11
- post = Post.new(id: 1337, title: 'New Post', blog: nil, body: 'Body', comments: comments, author: author)
12
- serializer = PostSerializer.new(post)
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)
13
24
  adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
14
25
  serialization = adapter.as_json
15
26
 
16
27
  Benchmark.ams('camel', time: time, disable_gc: disable_gc) do
17
- ActiveModelSerializers::KeyTransform.camel(serialization)
28
+ CaseTransform.camel(serialization)
18
29
  end
19
30
 
20
31
  Benchmark.ams('camel_lower', time: time, disable_gc: disable_gc) do
21
- ActiveModelSerializers::KeyTransform.camel_lower(serialization)
32
+ CaseTransform.camel_lower(serialization)
22
33
  end
23
34
 
24
35
  Benchmark.ams('dash', time: time, disable_gc: disable_gc) do
25
- ActiveModelSerializers::KeyTransform.dash(serialization)
36
+ CaseTransform.dash(serialization)
26
37
  end
27
38
 
28
39
  Benchmark.ams('unaltered', time: time, disable_gc: disable_gc) do
29
- ActiveModelSerializers::KeyTransform.unaltered(serialization)
40
+ CaseTransform.unaltered(serialization)
30
41
  end
31
42
 
32
43
  Benchmark.ams('underscore', time: time, disable_gc: disable_gc) do
33
- ActiveModelSerializers::KeyTransform.underscore(serialization)
44
+ CaseTransform.underscore(serialization)
34
45
  end