active_model_serializers 0.10.0 → 0.10.9

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