active_model_serializers_custom 0.10.90

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 (215) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE.md +29 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  4. data/.gitignore +35 -0
  5. data/.rubocop.yml +109 -0
  6. data/.simplecov +110 -0
  7. data/.travis.yml +63 -0
  8. data/CHANGELOG.md +727 -0
  9. data/CODE_OF_CONDUCT.md +74 -0
  10. data/CONTRIBUTING.md +105 -0
  11. data/Gemfile +74 -0
  12. data/MIT-LICENSE +22 -0
  13. data/README.md +305 -0
  14. data/Rakefile +76 -0
  15. data/active_model_serializers.gemspec +64 -0
  16. data/appveyor.yml +28 -0
  17. data/bin/bench +171 -0
  18. data/bin/bench_regression +316 -0
  19. data/bin/rubocop +38 -0
  20. data/bin/serve_benchmark +39 -0
  21. data/docs/README.md +41 -0
  22. data/docs/STYLE.md +58 -0
  23. data/docs/general/adapters.md +269 -0
  24. data/docs/general/caching.md +58 -0
  25. data/docs/general/configuration_options.md +185 -0
  26. data/docs/general/deserialization.md +100 -0
  27. data/docs/general/fields.md +31 -0
  28. data/docs/general/getting_started.md +133 -0
  29. data/docs/general/instrumentation.md +40 -0
  30. data/docs/general/key_transforms.md +40 -0
  31. data/docs/general/logging.md +21 -0
  32. data/docs/general/rendering.md +293 -0
  33. data/docs/general/serializers.md +495 -0
  34. data/docs/how-open-source-maintained.jpg +0 -0
  35. data/docs/howto/add_pagination_links.md +138 -0
  36. data/docs/howto/add_relationship_links.md +140 -0
  37. data/docs/howto/add_root_key.md +62 -0
  38. data/docs/howto/grape_integration.md +42 -0
  39. data/docs/howto/outside_controller_use.md +66 -0
  40. data/docs/howto/passing_arbitrary_options.md +27 -0
  41. data/docs/howto/serialize_poro.md +73 -0
  42. data/docs/howto/test.md +154 -0
  43. data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
  44. data/docs/integrations/ember-and-json-api.md +147 -0
  45. data/docs/integrations/grape.md +19 -0
  46. data/docs/jsonapi/errors.md +56 -0
  47. data/docs/jsonapi/schema.md +151 -0
  48. data/docs/jsonapi/schema/schema.json +366 -0
  49. data/docs/rfcs/0000-namespace.md +106 -0
  50. data/docs/rfcs/template.md +15 -0
  51. data/lib/action_controller/serialization.rb +76 -0
  52. data/lib/active_model/serializable_resource.rb +13 -0
  53. data/lib/active_model/serializer.rb +418 -0
  54. data/lib/active_model/serializer/adapter.rb +26 -0
  55. data/lib/active_model/serializer/adapter/attributes.rb +17 -0
  56. data/lib/active_model/serializer/adapter/base.rb +20 -0
  57. data/lib/active_model/serializer/adapter/json.rb +17 -0
  58. data/lib/active_model/serializer/adapter/json_api.rb +17 -0
  59. data/lib/active_model/serializer/adapter/null.rb +17 -0
  60. data/lib/active_model/serializer/array_serializer.rb +14 -0
  61. data/lib/active_model/serializer/association.rb +91 -0
  62. data/lib/active_model/serializer/attribute.rb +27 -0
  63. data/lib/active_model/serializer/belongs_to_reflection.rb +13 -0
  64. data/lib/active_model/serializer/collection_serializer.rb +90 -0
  65. data/lib/active_model/serializer/concerns/caching.rb +304 -0
  66. data/lib/active_model/serializer/error_serializer.rb +16 -0
  67. data/lib/active_model/serializer/errors_serializer.rb +34 -0
  68. data/lib/active_model/serializer/field.rb +92 -0
  69. data/lib/active_model/serializer/fieldset.rb +33 -0
  70. data/lib/active_model/serializer/has_many_reflection.rb +12 -0
  71. data/lib/active_model/serializer/has_one_reflection.rb +9 -0
  72. data/lib/active_model/serializer/lazy_association.rb +99 -0
  73. data/lib/active_model/serializer/link.rb +23 -0
  74. data/lib/active_model/serializer/lint.rb +152 -0
  75. data/lib/active_model/serializer/null.rb +19 -0
  76. data/lib/active_model/serializer/reflection.rb +212 -0
  77. data/lib/active_model/serializer/version.rb +7 -0
  78. data/lib/active_model_serializers.rb +63 -0
  79. data/lib/active_model_serializers/adapter.rb +100 -0
  80. data/lib/active_model_serializers/adapter/attributes.rb +15 -0
  81. data/lib/active_model_serializers/adapter/base.rb +85 -0
  82. data/lib/active_model_serializers/adapter/json.rb +23 -0
  83. data/lib/active_model_serializers/adapter/json_api.rb +535 -0
  84. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +215 -0
  85. data/lib/active_model_serializers/adapter/json_api/error.rb +98 -0
  86. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +51 -0
  87. data/lib/active_model_serializers/adapter/json_api/link.rb +85 -0
  88. data/lib/active_model_serializers/adapter/json_api/meta.rb +39 -0
  89. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +90 -0
  90. data/lib/active_model_serializers/adapter/json_api/relationship.rb +106 -0
  91. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +68 -0
  92. data/lib/active_model_serializers/adapter/null.rb +11 -0
  93. data/lib/active_model_serializers/callbacks.rb +57 -0
  94. data/lib/active_model_serializers/deprecate.rb +56 -0
  95. data/lib/active_model_serializers/deserialization.rb +17 -0
  96. data/lib/active_model_serializers/json_pointer.rb +16 -0
  97. data/lib/active_model_serializers/logging.rb +124 -0
  98. data/lib/active_model_serializers/lookup_chain.rb +82 -0
  99. data/lib/active_model_serializers/model.rb +132 -0
  100. data/lib/active_model_serializers/railtie.rb +52 -0
  101. data/lib/active_model_serializers/register_jsonapi_renderer.rb +80 -0
  102. data/lib/active_model_serializers/serializable_resource.rb +84 -0
  103. data/lib/active_model_serializers/serialization_context.rb +41 -0
  104. data/lib/active_model_serializers/test.rb +9 -0
  105. data/lib/active_model_serializers/test/schema.rb +140 -0
  106. data/lib/active_model_serializers/test/serializer.rb +127 -0
  107. data/lib/generators/rails/USAGE +6 -0
  108. data/lib/generators/rails/resource_override.rb +12 -0
  109. data/lib/generators/rails/serializer_generator.rb +38 -0
  110. data/lib/generators/rails/templates/serializer.rb.erb +8 -0
  111. data/lib/grape/active_model_serializers.rb +18 -0
  112. data/lib/grape/formatters/active_model_serializers.rb +34 -0
  113. data/lib/grape/helpers/active_model_serializers.rb +19 -0
  114. data/lib/tasks/rubocop.rake +55 -0
  115. data/test/action_controller/adapter_selector_test.rb +64 -0
  116. data/test/action_controller/explicit_serializer_test.rb +137 -0
  117. data/test/action_controller/json/include_test.rb +248 -0
  118. data/test/action_controller/json_api/deserialization_test.rb +114 -0
  119. data/test/action_controller/json_api/errors_test.rb +42 -0
  120. data/test/action_controller/json_api/fields_test.rb +68 -0
  121. data/test/action_controller/json_api/linked_test.rb +204 -0
  122. data/test/action_controller/json_api/pagination_test.rb +126 -0
  123. data/test/action_controller/json_api/transform_test.rb +191 -0
  124. data/test/action_controller/lookup_proc_test.rb +51 -0
  125. data/test/action_controller/namespace_lookup_test.rb +239 -0
  126. data/test/action_controller/serialization_scope_name_test.rb +237 -0
  127. data/test/action_controller/serialization_test.rb +480 -0
  128. data/test/active_model_serializers/adapter_for_test.rb +210 -0
  129. data/test/active_model_serializers/json_pointer_test.rb +24 -0
  130. data/test/active_model_serializers/logging_test.rb +79 -0
  131. data/test/active_model_serializers/model_test.rb +144 -0
  132. data/test/active_model_serializers/railtie_test_isolated.rb +70 -0
  133. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +163 -0
  134. data/test/active_model_serializers/serialization_context_test_isolated.rb +73 -0
  135. data/test/active_model_serializers/test/schema_test.rb +133 -0
  136. data/test/active_model_serializers/test/serializer_test.rb +64 -0
  137. data/test/active_record_test.rb +11 -0
  138. data/test/adapter/attributes_test.rb +42 -0
  139. data/test/adapter/deprecation_test.rb +102 -0
  140. data/test/adapter/json/belongs_to_test.rb +47 -0
  141. data/test/adapter/json/collection_test.rb +106 -0
  142. data/test/adapter/json/has_many_test.rb +55 -0
  143. data/test/adapter/json/transform_test.rb +95 -0
  144. data/test/adapter/json_api/belongs_to_test.rb +157 -0
  145. data/test/adapter/json_api/collection_test.rb +98 -0
  146. data/test/adapter/json_api/errors_test.rb +78 -0
  147. data/test/adapter/json_api/fields_test.rb +98 -0
  148. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
  149. data/test/adapter/json_api/has_many_test.rb +175 -0
  150. data/test/adapter/json_api/has_one_test.rb +82 -0
  151. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +215 -0
  152. data/test/adapter/json_api/json_api_test.rb +35 -0
  153. data/test/adapter/json_api/linked_test.rb +415 -0
  154. data/test/adapter/json_api/links_test.rb +112 -0
  155. data/test/adapter/json_api/pagination_links_test.rb +208 -0
  156. data/test/adapter/json_api/parse_test.rb +139 -0
  157. data/test/adapter/json_api/relationship_test.rb +399 -0
  158. data/test/adapter/json_api/resource_meta_test.rb +102 -0
  159. data/test/adapter/json_api/toplevel_jsonapi_test.rb +84 -0
  160. data/test/adapter/json_api/transform_test.rb +514 -0
  161. data/test/adapter/json_api/type_test.rb +195 -0
  162. data/test/adapter/json_test.rb +48 -0
  163. data/test/adapter/null_test.rb +24 -0
  164. data/test/adapter/polymorphic_test.rb +220 -0
  165. data/test/adapter_test.rb +69 -0
  166. data/test/array_serializer_test.rb +24 -0
  167. data/test/benchmark/app.rb +67 -0
  168. data/test/benchmark/benchmarking_support.rb +69 -0
  169. data/test/benchmark/bm_active_record.rb +83 -0
  170. data/test/benchmark/bm_adapter.rb +40 -0
  171. data/test/benchmark/bm_caching.rb +121 -0
  172. data/test/benchmark/bm_lookup_chain.rb +85 -0
  173. data/test/benchmark/bm_transform.rb +47 -0
  174. data/test/benchmark/config.ru +3 -0
  175. data/test/benchmark/controllers.rb +85 -0
  176. data/test/benchmark/fixtures.rb +221 -0
  177. data/test/cache_test.rb +717 -0
  178. data/test/collection_serializer_test.rb +129 -0
  179. data/test/fixtures/active_record.rb +115 -0
  180. data/test/fixtures/poro.rb +227 -0
  181. data/test/generators/scaffold_controller_generator_test.rb +26 -0
  182. data/test/generators/serializer_generator_test.rb +77 -0
  183. data/test/grape_test.rb +198 -0
  184. data/test/lint_test.rb +51 -0
  185. data/test/logger_test.rb +22 -0
  186. data/test/poro_test.rb +11 -0
  187. data/test/serializable_resource_test.rb +81 -0
  188. data/test/serializers/association_macros_test.rb +39 -0
  189. data/test/serializers/associations_test.rb +520 -0
  190. data/test/serializers/attribute_test.rb +155 -0
  191. data/test/serializers/attributes_test.rb +54 -0
  192. data/test/serializers/caching_configuration_test_isolated.rb +172 -0
  193. data/test/serializers/configuration_test.rb +34 -0
  194. data/test/serializers/fieldset_test.rb +16 -0
  195. data/test/serializers/meta_test.rb +204 -0
  196. data/test/serializers/options_test.rb +34 -0
  197. data/test/serializers/read_attribute_for_serialization_test.rb +81 -0
  198. data/test/serializers/reflection_test.rb +481 -0
  199. data/test/serializers/root_test.rb +23 -0
  200. data/test/serializers/serialization_test.rb +57 -0
  201. data/test/serializers/serializer_for_test.rb +138 -0
  202. data/test/serializers/serializer_for_with_namespace_test.rb +90 -0
  203. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  204. data/test/support/isolated_unit.rb +86 -0
  205. data/test/support/rails5_shims.rb +55 -0
  206. data/test/support/rails_app.rb +40 -0
  207. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  208. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
  209. data/test/support/schemas/custom/show.json +7 -0
  210. data/test/support/schemas/hyper_schema.json +93 -0
  211. data/test/support/schemas/render_using_json_api.json +43 -0
  212. data/test/support/schemas/simple_json_pointers.json +10 -0
  213. data/test/support/serialization_testing.rb +81 -0
  214. data/test/test_helper.rb +72 -0
  215. metadata +622 -0
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ module ActiveModel
6
+ class Serializer
7
+ class AssociationMacrosTest < ActiveSupport::TestCase
8
+ class AuthorSummarySerializer < ActiveModel::Serializer; end
9
+
10
+ class AssociationsTestSerializer < Serializer
11
+ belongs_to :author, serializer: AuthorSummarySerializer
12
+ has_many :comments
13
+ has_one :category
14
+ end
15
+
16
+ def before_setup
17
+ @reflections = AssociationsTestSerializer._reflections.values
18
+ end
19
+
20
+ def test_has_one_defines_reflection
21
+ has_one_reflection = HasOneReflection.new(:category, {})
22
+
23
+ assert_includes(@reflections, has_one_reflection)
24
+ end
25
+
26
+ def test_has_many_defines_reflection
27
+ has_many_reflection = HasManyReflection.new(:comments, {})
28
+
29
+ assert_includes(@reflections, has_many_reflection)
30
+ end
31
+
32
+ def test_belongs_to_defines_reflection
33
+ belongs_to_reflection = BelongsToReflection.new(:author, serializer: AuthorSummarySerializer)
34
+
35
+ assert_includes(@reflections, belongs_to_reflection)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,520 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ module ActiveModel
5
+ class Serializer
6
+ class AssociationsTest < ActiveSupport::TestCase
7
+ class ModelWithoutSerializer < ::Model
8
+ attributes :id, :name
9
+ end
10
+
11
+ def setup
12
+ @author = Author.new(name: 'Steve K.')
13
+ @author.bio = nil
14
+ @author.roles = []
15
+ @blog = Blog.new(name: 'AMS Blog')
16
+ @post = Post.new(title: 'New Post', body: 'Body')
17
+ @tag = ModelWithoutSerializer.new(id: 'tagid', name: '#hashtagged')
18
+ @comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
19
+ @post.comments = [@comment]
20
+ @post.tags = [@tag]
21
+ @post.blog = @blog
22
+ @comment.post = @post
23
+ @comment.author = nil
24
+ @post.author = @author
25
+ @author.posts = [@post]
26
+
27
+ @post_serializer = PostSerializer.new(@post, custom_options: true)
28
+ @author_serializer = AuthorSerializer.new(@author)
29
+ @comment_serializer = CommentSerializer.new(@comment)
30
+ end
31
+
32
+ def test_has_many_and_has_one
33
+ @author_serializer.associations.each do |association|
34
+ key = association.key
35
+ serializer = association.lazy_association.serializer
36
+
37
+ case key
38
+ when :posts
39
+ assert_equal true, association.include_data?
40
+ assert_kind_of(ActiveModelSerializers.config.collection_serializer, serializer)
41
+ when :bio
42
+ assert_equal true, association.include_data?
43
+ assert_nil serializer
44
+ when :roles
45
+ assert_equal true, association.include_data?
46
+ assert_kind_of(ActiveModelSerializers.config.collection_serializer, serializer)
47
+ else
48
+ flunk "Unknown association: #{key}"
49
+ end
50
+ end
51
+ end
52
+
53
+ def test_has_many_with_no_serializer
54
+ post_serializer_class = Class.new(ActiveModel::Serializer) do
55
+ attributes :id
56
+ has_many :tags
57
+ end
58
+ post_serializer_class.new(@post).associations.each do |association|
59
+ key = association.key
60
+ serializer = association.lazy_association.serializer
61
+
62
+ assert_equal :tags, key
63
+ assert_nil serializer
64
+ assert_equal [{ id: 'tagid', name: '#hashtagged' }].to_json, association.virtual_value.to_json
65
+ end
66
+ end
67
+
68
+ def test_serializer_options_are_passed_into_associations_serializers
69
+ association = @post_serializer
70
+ .associations
71
+ .detect { |assoc| assoc.key == :comments }
72
+
73
+ comment_serializer = association.lazy_association.serializer.first
74
+ class << comment_serializer
75
+ def custom_options
76
+ instance_options
77
+ end
78
+ end
79
+ assert comment_serializer.custom_options.fetch(:custom_options)
80
+ end
81
+
82
+ def test_belongs_to
83
+ @comment_serializer.associations.each do |association|
84
+ key = association.key
85
+ serializer = association.lazy_association.serializer
86
+
87
+ case key
88
+ when :post
89
+ assert_kind_of(PostSerializer, serializer)
90
+ when :author
91
+ assert_nil serializer
92
+ else
93
+ flunk "Unknown association: #{key}"
94
+ end
95
+
96
+ assert_equal true, association.include_data?
97
+ end
98
+ end
99
+
100
+ def test_belongs_to_with_custom_method
101
+ assert(
102
+ @post_serializer.associations.any? do |association|
103
+ association.key == :blog
104
+ end
105
+ )
106
+ end
107
+
108
+ def test_associations_inheritance
109
+ inherited_klass = Class.new(PostSerializer)
110
+
111
+ assert_equal(PostSerializer._reflections, inherited_klass._reflections)
112
+ end
113
+
114
+ def test_associations_inheritance_with_new_association
115
+ inherited_klass = Class.new(PostSerializer) do
116
+ has_many :top_comments, serializer: CommentSerializer
117
+ end
118
+
119
+ assert(
120
+ PostSerializer._reflections.values.all? do |reflection|
121
+ inherited_klass._reflections.values.include?(reflection)
122
+ end
123
+ )
124
+
125
+ assert(
126
+ inherited_klass._reflections.values.any? do |reflection|
127
+ reflection.name == :top_comments
128
+ end
129
+ )
130
+ end
131
+
132
+ def test_associations_custom_keys
133
+ serializer = PostWithCustomKeysSerializer.new(@post)
134
+
135
+ expected_association_keys = serializer.associations.map(&:key)
136
+
137
+ assert expected_association_keys.include? :reviews
138
+ assert expected_association_keys.include? :writer
139
+ assert expected_association_keys.include? :site
140
+ end
141
+
142
+ class BelongsToBlogModel < ::Model
143
+ attributes :id, :title
144
+ associations :blog
145
+ end
146
+ class BelongsToBlogModelSerializer < ActiveModel::Serializer
147
+ type :posts
148
+ belongs_to :blog
149
+ end
150
+
151
+ def test_belongs_to_doesnt_load_record
152
+ attributes = { id: 1, title: 'Belongs to Blog', blog: Blog.new(id: 5) }
153
+ post = BelongsToBlogModel.new(attributes)
154
+ class << post
155
+ def blog
156
+ fail 'should use blog_id'
157
+ end
158
+
159
+ def blog_id
160
+ 5
161
+ end
162
+ end
163
+
164
+ actual =
165
+ begin
166
+ original_option = BelongsToBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship
167
+ BelongsToBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = true
168
+ serializable(post, adapter: :json_api, serializer: BelongsToBlogModelSerializer).as_json
169
+ ensure
170
+ BelongsToBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = original_option
171
+ end
172
+ expected = { data: { id: '1', type: 'posts', relationships: { blog: { data: { id: '5', type: 'blogs' } } } } }
173
+
174
+ assert_equal expected, actual
175
+ end
176
+
177
+ class ExternalBlog < Blog
178
+ attributes :external_id
179
+ end
180
+ class BelongsToExternalBlogModel < ::Model
181
+ attributes :id, :title, :external_blog_id
182
+ associations :external_blog
183
+ end
184
+ class BelongsToExternalBlogModelSerializer < ActiveModel::Serializer
185
+ type :posts
186
+ belongs_to :external_blog
187
+
188
+ def external_blog_id
189
+ object.external_blog.external_id
190
+ end
191
+ end
192
+
193
+ def test_belongs_to_allows_id_overwriting
194
+ attributes = {
195
+ id: 1,
196
+ title: 'Title',
197
+ external_blog: ExternalBlog.new(id: 5, external_id: 6)
198
+ }
199
+ post = BelongsToExternalBlogModel.new(attributes)
200
+
201
+ actual =
202
+ begin
203
+ original_option = BelongsToExternalBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship
204
+ BelongsToExternalBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = true
205
+ serializable(post, adapter: :json_api, serializer: BelongsToExternalBlogModelSerializer).as_json
206
+ ensure
207
+ BelongsToExternalBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = original_option
208
+ end
209
+ expected = { data: { id: '1', type: 'posts', relationships: { :'external-blog' => { data: { id: '6', type: 'external-blogs' } } } } }
210
+
211
+ assert_equal expected, actual
212
+ end
213
+
214
+ class InlineAssociationTestPostSerializer < ActiveModel::Serializer
215
+ has_many :comments
216
+ has_many :comments, key: :last_comments do
217
+ object.comments.last(1)
218
+ end
219
+ end
220
+
221
+ def test_virtual_attribute_block
222
+ comment1 = ::ARModels::Comment.create!(contents: 'first comment')
223
+ comment2 = ::ARModels::Comment.create!(contents: 'last comment')
224
+ post = ::ARModels::Post.create!(
225
+ title: 'inline association test',
226
+ body: 'etc',
227
+ comments: [comment1, comment2]
228
+ )
229
+ actual = serializable(post, adapter: :attributes, serializer: InlineAssociationTestPostSerializer).as_json
230
+ expected = {
231
+ comments: [
232
+ { id: 1, contents: 'first comment' },
233
+ { id: 2, contents: 'last comment' }
234
+ ],
235
+ last_comments: [
236
+ { id: 2, contents: 'last comment' }
237
+ ]
238
+ }
239
+
240
+ assert_equal expected, actual
241
+ ensure
242
+ ::ARModels::Post.delete_all
243
+ ::ARModels::Comment.delete_all
244
+ end
245
+
246
+ class NamespacedResourcesTest < ActiveSupport::TestCase
247
+ class ResourceNamespace
248
+ class Post < ::Model
249
+ associations :comments, :author, :description
250
+ end
251
+ class Comment < ::Model; end
252
+ class Author < ::Model; end
253
+ class Description < ::Model; end
254
+ class PostSerializer < ActiveModel::Serializer
255
+ has_many :comments
256
+ belongs_to :author
257
+ has_one :description
258
+ end
259
+ class CommentSerializer < ActiveModel::Serializer; end
260
+ class AuthorSerializer < ActiveModel::Serializer; end
261
+ class DescriptionSerializer < ActiveModel::Serializer; end
262
+ end
263
+
264
+ def setup
265
+ @comment = ResourceNamespace::Comment.new
266
+ @author = ResourceNamespace::Author.new
267
+ @description = ResourceNamespace::Description.new
268
+ @post = ResourceNamespace::Post.new(comments: [@comment],
269
+ author: @author,
270
+ description: @description)
271
+ @post_serializer = ResourceNamespace::PostSerializer.new(@post)
272
+ end
273
+
274
+ def test_associations_namespaced_resources
275
+ @post_serializer.associations.each do |association|
276
+ case association.key
277
+ when :comments
278
+ assert_instance_of(ResourceNamespace::CommentSerializer, association.lazy_association.serializer.first)
279
+ when :author
280
+ assert_instance_of(ResourceNamespace::AuthorSerializer, association.lazy_association.serializer)
281
+ when :description
282
+ assert_instance_of(ResourceNamespace::DescriptionSerializer, association.lazy_association.serializer)
283
+ else
284
+ flunk "Unknown association: #{key}"
285
+ end
286
+ end
287
+ end
288
+ end
289
+
290
+ class AssociationsNamespacedSerializersTest < ActiveSupport::TestCase
291
+ class Post < ::Model
292
+ associations :comments, :author, :description
293
+
294
+ def latest_comments
295
+ comments[0..3]
296
+ end
297
+ end
298
+ class Comment < ::Model; end
299
+ class Author < ::Model; end
300
+ class Description < ::Model; end
301
+
302
+ class ResourceNamespace
303
+ class PostSerializer < ActiveModel::Serializer
304
+ has_many :comments, namespace: ResourceNamespace
305
+ has_many :latest_comments, namespace: ResourceNamespace
306
+ belongs_to :author, namespace: ResourceNamespace
307
+ has_one :description, namespace: ResourceNamespace
308
+ end
309
+ class CommentSerializer < ActiveModel::Serializer; end
310
+ class AuthorSerializer < ActiveModel::Serializer; end
311
+ class DescriptionSerializer < ActiveModel::Serializer; end
312
+ end
313
+
314
+ def setup
315
+ @comment = Comment.new
316
+ @author = Author.new
317
+ @description = Description.new
318
+ @post = Post.new(comments: [@comment],
319
+ author: @author,
320
+ description: @description)
321
+ @post_serializer = ResourceNamespace::PostSerializer.new(@post)
322
+ end
323
+
324
+ def test_associations_namespaced_serializers
325
+ @post_serializer.associations.each do |association|
326
+ case association.key
327
+ when :comments, :latest_comments
328
+ assert_instance_of(ResourceNamespace::CommentSerializer, association.lazy_association.serializer.first)
329
+ when :author
330
+ assert_instance_of(ResourceNamespace::AuthorSerializer, association.lazy_association.serializer)
331
+ when :description
332
+ assert_instance_of(ResourceNamespace::DescriptionSerializer, association.lazy_association.serializer)
333
+ else
334
+ flunk "Unknown association: #{key}"
335
+ end
336
+ end
337
+ end
338
+ end
339
+
340
+ class NestedSerializersTest < ActiveSupport::TestCase
341
+ class Post < ::Model
342
+ associations :comments, :author, :description
343
+ end
344
+ class Comment < ::Model; end
345
+ class Author < ::Model; end
346
+ class Description < ::Model; end
347
+ class PostSerializer < ActiveModel::Serializer
348
+ has_many :comments
349
+ class CommentSerializer < ActiveModel::Serializer; end
350
+ belongs_to :author
351
+ class AuthorSerializer < ActiveModel::Serializer; end
352
+ has_one :description
353
+ class DescriptionSerializer < ActiveModel::Serializer; end
354
+ end
355
+
356
+ def setup
357
+ @comment = Comment.new
358
+ @author = Author.new
359
+ @description = Description.new
360
+ @post = Post.new(comments: [@comment],
361
+ author: @author,
362
+ description: @description)
363
+ @post_serializer = PostSerializer.new(@post)
364
+ end
365
+
366
+ def test_associations_namespaced_resources
367
+ @post_serializer.associations.each do |association|
368
+ case association.key
369
+ when :comments
370
+ assert_instance_of(PostSerializer::CommentSerializer, association.lazy_association.serializer.first)
371
+ when :author
372
+ assert_instance_of(PostSerializer::AuthorSerializer, association.lazy_association.serializer)
373
+ when :description
374
+ assert_instance_of(PostSerializer::DescriptionSerializer, association.lazy_association.serializer)
375
+ else
376
+ flunk "Unknown association: #{key}"
377
+ end
378
+ end
379
+ end
380
+
381
+ # rubocop:disable Metrics/AbcSize
382
+ def test_conditional_associations
383
+ model = Class.new(::Model) do
384
+ attributes :true, :false
385
+ associations :something
386
+ end.new(true: true, false: false)
387
+
388
+ scenarios = [
389
+ { options: { if: :true }, included: true },
390
+ { options: { if: :false }, included: false },
391
+ { options: { unless: :false }, included: true },
392
+ { options: { unless: :true }, included: false },
393
+ { options: { if: 'object.true' }, included: true },
394
+ { options: { if: 'object.false' }, included: false },
395
+ { options: { unless: 'object.false' }, included: true },
396
+ { options: { unless: 'object.true' }, included: false },
397
+ { options: { if: -> { object.true } }, included: true },
398
+ { options: { if: -> { object.false } }, included: false },
399
+ { options: { unless: -> { object.false } }, included: true },
400
+ { options: { unless: -> { object.true } }, included: false },
401
+ { options: { if: -> (s) { s.object.true } }, included: true },
402
+ { options: { if: -> (s) { s.object.false } }, included: false },
403
+ { options: { unless: -> (s) { s.object.false } }, included: true },
404
+ { options: { unless: -> (s) { s.object.true } }, included: false }
405
+ ]
406
+
407
+ scenarios.each do |s|
408
+ serializer = Class.new(ActiveModel::Serializer) do
409
+ belongs_to :something, s[:options]
410
+
411
+ def true
412
+ true
413
+ end
414
+
415
+ def false
416
+ false
417
+ end
418
+ end
419
+
420
+ hash = serializable(model, serializer: serializer).serializable_hash
421
+ assert_equal(s[:included], hash.key?(:something), "Error with #{s[:options]}")
422
+ end
423
+ end
424
+
425
+ def test_illegal_conditional_associations
426
+ exception = assert_raises(TypeError) do
427
+ Class.new(ActiveModel::Serializer) do
428
+ belongs_to :x, if: nil
429
+ end
430
+ end
431
+
432
+ assert_match(/:if should be a Symbol, String or Proc/, exception.message)
433
+ end
434
+ end
435
+
436
+ class InheritedSerializerTest < ActiveSupport::TestCase
437
+ class PostSerializer < ActiveModel::Serializer
438
+ belongs_to :author
439
+ has_many :comments
440
+ belongs_to :blog
441
+ end
442
+
443
+ class InheritedPostSerializer < PostSerializer
444
+ belongs_to :author, polymorphic: true
445
+ has_many :comments, key: :reviews
446
+ end
447
+
448
+ class AuthorSerializer < ActiveModel::Serializer
449
+ has_many :posts
450
+ has_many :roles
451
+ has_one :bio
452
+ end
453
+
454
+ class InheritedAuthorSerializer < AuthorSerializer
455
+ has_many :roles, polymorphic: true
456
+ has_one :bio, polymorphic: true
457
+ end
458
+
459
+ def setup
460
+ @author = Author.new(name: 'Steve K.')
461
+ @post = Post.new(title: 'New Post', body: 'Body')
462
+ @post_serializer = PostSerializer.new(@post)
463
+ @author_serializer = AuthorSerializer.new(@author)
464
+ @inherited_post_serializer = InheritedPostSerializer.new(@post)
465
+ @inherited_author_serializer = InheritedAuthorSerializer.new(@author)
466
+ @author_associations = @author_serializer.associations.to_a.sort_by(&:name)
467
+ @inherited_author_associations = @inherited_author_serializer.associations.to_a.sort_by(&:name)
468
+ @post_associations = @post_serializer.associations.to_a
469
+ @inherited_post_associations = @inherited_post_serializer.associations.to_a
470
+ end
471
+
472
+ test 'an author serializer must have [posts,roles,bio] associations' do
473
+ expected = [:posts, :roles, :bio].sort
474
+ result = @author_serializer.associations.map(&:name).sort
475
+ assert_equal(result, expected)
476
+ end
477
+
478
+ test 'a post serializer must have [author,comments,blog] associations' do
479
+ expected = [:author, :comments, :blog].sort
480
+ result = @post_serializer.associations.map(&:name).sort
481
+ assert_equal(result, expected)
482
+ end
483
+
484
+ test 'a serializer inheriting from another serializer can redefine has_many and has_one associations' do
485
+ expected = [:roles, :bio].sort
486
+ result = (@inherited_author_associations.map(&:reflection) - @author_associations.map(&:reflection)).map(&:name)
487
+ assert_equal(result, expected)
488
+ assert_equal [true, false, true], @inherited_author_associations.map(&:polymorphic?)
489
+ assert_equal [false, false, false], @author_associations.map(&:polymorphic?)
490
+ end
491
+
492
+ test 'a serializer inheriting from another serializer can redefine belongs_to associations' do
493
+ assert_equal [:author, :comments, :blog], @post_associations.map(&:name)
494
+ assert_equal [:author, :comments, :blog, :comments], @inherited_post_associations.map(&:name)
495
+
496
+ refute @post_associations.detect { |assoc| assoc.name == :author }.polymorphic?
497
+ assert @inherited_post_associations.detect { |assoc| assoc.name == :author }.polymorphic?
498
+
499
+ refute @post_associations.detect { |assoc| assoc.name == :comments }.key?
500
+ original_comment_assoc, new_comments_assoc = @inherited_post_associations.select { |assoc| assoc.name == :comments }
501
+ refute original_comment_assoc.key?
502
+ assert_equal :reviews, new_comments_assoc.key
503
+
504
+ original_blog = @post_associations.detect { |assoc| assoc.name == :blog }
505
+ inherited_blog = @inherited_post_associations.detect { |assoc| assoc.name == :blog }
506
+ original_parent_serializer = original_blog.lazy_association.association_options.delete(:parent_serializer)
507
+ inherited_parent_serializer = inherited_blog.lazy_association.association_options.delete(:parent_serializer)
508
+ assert_equal PostSerializer, original_parent_serializer.class
509
+ assert_equal InheritedPostSerializer, inherited_parent_serializer.class
510
+ end
511
+
512
+ test 'a serializer inheriting from another serializer can have an additional association with the same name but with different key' do
513
+ expected = [:author, :comments, :blog, :reviews].sort
514
+ result = @inherited_post_serializer.associations.map(&:key).sort
515
+ assert_equal(result, expected)
516
+ end
517
+ end
518
+ end
519
+ end
520
+ end