agi_active_model_serializers 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 (220) 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 +102 -0
  6. data/.simplecov +110 -0
  7. data/.travis.yml +51 -0
  8. data/CHANGELOG.md +612 -0
  9. data/CODE_OF_CONDUCT.md +74 -0
  10. data/CONTRIBUTING.md +105 -0
  11. data/Gemfile +56 -0
  12. data/MIT-LICENSE +22 -0
  13. data/README.md +307 -0
  14. data/Rakefile +103 -0
  15. data/active_model_serializers.gemspec +63 -0
  16. data/appveyor.yml +24 -0
  17. data/bin/bench +171 -0
  18. data/bin/bench_regression +316 -0
  19. data/bin/serve_benchmark +39 -0
  20. data/docs/README.md +41 -0
  21. data/docs/STYLE.md +58 -0
  22. data/docs/general/adapters.md +247 -0
  23. data/docs/general/caching.md +58 -0
  24. data/docs/general/configuration_options.md +169 -0
  25. data/docs/general/deserialization.md +100 -0
  26. data/docs/general/fields.md +31 -0
  27. data/docs/general/getting_started.md +133 -0
  28. data/docs/general/instrumentation.md +40 -0
  29. data/docs/general/key_transforms.md +40 -0
  30. data/docs/general/logging.md +14 -0
  31. data/docs/general/rendering.md +279 -0
  32. data/docs/general/serializers.md +461 -0
  33. data/docs/how-open-source-maintained.jpg +0 -0
  34. data/docs/howto/add_pagination_links.md +138 -0
  35. data/docs/howto/add_relationship_links.md +137 -0
  36. data/docs/howto/add_root_key.md +55 -0
  37. data/docs/howto/grape_integration.md +42 -0
  38. data/docs/howto/outside_controller_use.md +65 -0
  39. data/docs/howto/passing_arbitrary_options.md +27 -0
  40. data/docs/howto/serialize_poro.md +32 -0
  41. data/docs/howto/test.md +154 -0
  42. data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
  43. data/docs/integrations/ember-and-json-api.md +144 -0
  44. data/docs/integrations/grape.md +19 -0
  45. data/docs/jsonapi/errors.md +56 -0
  46. data/docs/jsonapi/schema.md +151 -0
  47. data/docs/jsonapi/schema/schema.json +366 -0
  48. data/docs/rfcs/0000-namespace.md +106 -0
  49. data/docs/rfcs/template.md +15 -0
  50. data/lib/action_controller/serialization.rb +66 -0
  51. data/lib/active_model/serializable_resource.rb +11 -0
  52. data/lib/active_model/serializer.rb +231 -0
  53. data/lib/active_model/serializer/adapter.rb +24 -0
  54. data/lib/active_model/serializer/adapter/attributes.rb +15 -0
  55. data/lib/active_model/serializer/adapter/base.rb +18 -0
  56. data/lib/active_model/serializer/adapter/json.rb +15 -0
  57. data/lib/active_model/serializer/adapter/json_api.rb +15 -0
  58. data/lib/active_model/serializer/adapter/null.rb +15 -0
  59. data/lib/active_model/serializer/array_serializer.rb +12 -0
  60. data/lib/active_model/serializer/association.rb +34 -0
  61. data/lib/active_model/serializer/attribute.rb +25 -0
  62. data/lib/active_model/serializer/belongs_to_reflection.rb +7 -0
  63. data/lib/active_model/serializer/collection_reflection.rb +7 -0
  64. data/lib/active_model/serializer/collection_serializer.rb +87 -0
  65. data/lib/active_model/serializer/concerns/associations.rb +102 -0
  66. data/lib/active_model/serializer/concerns/attributes.rb +82 -0
  67. data/lib/active_model/serializer/concerns/caching.rb +292 -0
  68. data/lib/active_model/serializer/concerns/configuration.rb +59 -0
  69. data/lib/active_model/serializer/concerns/links.rb +35 -0
  70. data/lib/active_model/serializer/concerns/meta.rb +29 -0
  71. data/lib/active_model/serializer/concerns/type.rb +25 -0
  72. data/lib/active_model/serializer/error_serializer.rb +14 -0
  73. data/lib/active_model/serializer/errors_serializer.rb +32 -0
  74. data/lib/active_model/serializer/field.rb +90 -0
  75. data/lib/active_model/serializer/fieldset.rb +31 -0
  76. data/lib/active_model/serializer/has_many_reflection.rb +7 -0
  77. data/lib/active_model/serializer/has_one_reflection.rb +7 -0
  78. data/lib/active_model/serializer/lint.rb +150 -0
  79. data/lib/active_model/serializer/null.rb +17 -0
  80. data/lib/active_model/serializer/reflection.rb +163 -0
  81. data/lib/active_model/serializer/singular_reflection.rb +7 -0
  82. data/lib/active_model/serializer/version.rb +5 -0
  83. data/lib/active_model_serializers.rb +53 -0
  84. data/lib/active_model_serializers/adapter.rb +98 -0
  85. data/lib/active_model_serializers/adapter/attributes.rb +13 -0
  86. data/lib/active_model_serializers/adapter/base.rb +83 -0
  87. data/lib/active_model_serializers/adapter/json.rb +21 -0
  88. data/lib/active_model_serializers/adapter/json_api.rb +517 -0
  89. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +213 -0
  90. data/lib/active_model_serializers/adapter/json_api/error.rb +96 -0
  91. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +49 -0
  92. data/lib/active_model_serializers/adapter/json_api/link.rb +83 -0
  93. data/lib/active_model_serializers/adapter/json_api/meta.rb +37 -0
  94. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +69 -0
  95. data/lib/active_model_serializers/adapter/json_api/relationship.rb +63 -0
  96. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +51 -0
  97. data/lib/active_model_serializers/adapter/null.rb +9 -0
  98. data/lib/active_model_serializers/callbacks.rb +55 -0
  99. data/lib/active_model_serializers/deprecate.rb +54 -0
  100. data/lib/active_model_serializers/deserialization.rb +15 -0
  101. data/lib/active_model_serializers/json_pointer.rb +14 -0
  102. data/lib/active_model_serializers/logging.rb +122 -0
  103. data/lib/active_model_serializers/lookup_chain.rb +80 -0
  104. data/lib/active_model_serializers/model.rb +71 -0
  105. data/lib/active_model_serializers/railtie.rb +48 -0
  106. data/lib/active_model_serializers/register_jsonapi_renderer.rb +78 -0
  107. data/lib/active_model_serializers/serializable_resource.rb +82 -0
  108. data/lib/active_model_serializers/serialization_context.rb +39 -0
  109. data/lib/active_model_serializers/test.rb +7 -0
  110. data/lib/active_model_serializers/test/schema.rb +138 -0
  111. data/lib/active_model_serializers/test/serializer.rb +125 -0
  112. data/lib/generators/rails/USAGE +6 -0
  113. data/lib/generators/rails/resource_override.rb +10 -0
  114. data/lib/generators/rails/serializer_generator.rb +36 -0
  115. data/lib/generators/rails/templates/serializer.rb.erb +15 -0
  116. data/lib/grape/active_model_serializers.rb +16 -0
  117. data/lib/grape/formatters/active_model_serializers.rb +32 -0
  118. data/lib/grape/helpers/active_model_serializers.rb +17 -0
  119. data/test/action_controller/adapter_selector_test.rb +53 -0
  120. data/test/action_controller/explicit_serializer_test.rb +135 -0
  121. data/test/action_controller/json/include_test.rb +246 -0
  122. data/test/action_controller/json_api/deserialization_test.rb +112 -0
  123. data/test/action_controller/json_api/errors_test.rb +40 -0
  124. data/test/action_controller/json_api/fields_test.rb +66 -0
  125. data/test/action_controller/json_api/linked_test.rb +202 -0
  126. data/test/action_controller/json_api/pagination_test.rb +116 -0
  127. data/test/action_controller/json_api/transform_test.rb +189 -0
  128. data/test/action_controller/lookup_proc_test.rb +49 -0
  129. data/test/action_controller/namespace_lookup_test.rb +232 -0
  130. data/test/action_controller/serialization_scope_name_test.rb +229 -0
  131. data/test/action_controller/serialization_test.rb +472 -0
  132. data/test/active_model_serializers/adapter_for_test.rb +208 -0
  133. data/test/active_model_serializers/json_pointer_test.rb +22 -0
  134. data/test/active_model_serializers/logging_test.rb +77 -0
  135. data/test/active_model_serializers/model_test.rb +69 -0
  136. data/test/active_model_serializers/railtie_test_isolated.rb +63 -0
  137. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +161 -0
  138. data/test/active_model_serializers/serialization_context_test_isolated.rb +71 -0
  139. data/test/active_model_serializers/test/schema_test.rb +131 -0
  140. data/test/active_model_serializers/test/serializer_test.rb +62 -0
  141. data/test/active_record_test.rb +9 -0
  142. data/test/adapter/attributes_test.rb +43 -0
  143. data/test/adapter/deprecation_test.rb +100 -0
  144. data/test/adapter/json/belongs_to_test.rb +45 -0
  145. data/test/adapter/json/collection_test.rb +104 -0
  146. data/test/adapter/json/has_many_test.rb +45 -0
  147. data/test/adapter/json/transform_test.rb +93 -0
  148. data/test/adapter/json_api/belongs_to_test.rb +155 -0
  149. data/test/adapter/json_api/collection_test.rb +96 -0
  150. data/test/adapter/json_api/errors_test.rb +76 -0
  151. data/test/adapter/json_api/fields_test.rb +96 -0
  152. data/test/adapter/json_api/has_many_embed_ids_test.rb +43 -0
  153. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +96 -0
  154. data/test/adapter/json_api/has_many_test.rb +165 -0
  155. data/test/adapter/json_api/has_one_test.rb +80 -0
  156. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +168 -0
  157. data/test/adapter/json_api/json_api_test.rb +33 -0
  158. data/test/adapter/json_api/linked_test.rb +413 -0
  159. data/test/adapter/json_api/links_test.rb +95 -0
  160. data/test/adapter/json_api/pagination_links_test.rb +193 -0
  161. data/test/adapter/json_api/parse_test.rb +137 -0
  162. data/test/adapter/json_api/relationship_test.rb +397 -0
  163. data/test/adapter/json_api/resource_identifier_test.rb +110 -0
  164. data/test/adapter/json_api/resource_meta_test.rb +100 -0
  165. data/test/adapter/json_api/toplevel_jsonapi_test.rb +82 -0
  166. data/test/adapter/json_api/transform_test.rb +512 -0
  167. data/test/adapter/json_api/type_test.rb +61 -0
  168. data/test/adapter/json_test.rb +46 -0
  169. data/test/adapter/null_test.rb +22 -0
  170. data/test/adapter/polymorphic_test.rb +171 -0
  171. data/test/adapter_test.rb +67 -0
  172. data/test/array_serializer_test.rb +22 -0
  173. data/test/benchmark/app.rb +65 -0
  174. data/test/benchmark/benchmarking_support.rb +67 -0
  175. data/test/benchmark/bm_active_record.rb +81 -0
  176. data/test/benchmark/bm_adapter.rb +38 -0
  177. data/test/benchmark/bm_caching.rb +119 -0
  178. data/test/benchmark/bm_lookup_chain.rb +83 -0
  179. data/test/benchmark/bm_transform.rb +45 -0
  180. data/test/benchmark/config.ru +3 -0
  181. data/test/benchmark/controllers.rb +83 -0
  182. data/test/benchmark/fixtures.rb +219 -0
  183. data/test/cache_test.rb +595 -0
  184. data/test/collection_serializer_test.rb +123 -0
  185. data/test/fixtures/active_record.rb +113 -0
  186. data/test/fixtures/poro.rb +232 -0
  187. data/test/generators/scaffold_controller_generator_test.rb +24 -0
  188. data/test/generators/serializer_generator_test.rb +74 -0
  189. data/test/grape_test.rb +178 -0
  190. data/test/lint_test.rb +49 -0
  191. data/test/logger_test.rb +20 -0
  192. data/test/poro_test.rb +9 -0
  193. data/test/serializable_resource_test.rb +79 -0
  194. data/test/serializers/association_macros_test.rb +37 -0
  195. data/test/serializers/associations_test.rb +383 -0
  196. data/test/serializers/attribute_test.rb +153 -0
  197. data/test/serializers/attributes_test.rb +52 -0
  198. data/test/serializers/caching_configuration_test_isolated.rb +170 -0
  199. data/test/serializers/configuration_test.rb +32 -0
  200. data/test/serializers/fieldset_test.rb +14 -0
  201. data/test/serializers/meta_test.rb +202 -0
  202. data/test/serializers/options_test.rb +32 -0
  203. data/test/serializers/read_attribute_for_serialization_test.rb +79 -0
  204. data/test/serializers/root_test.rb +21 -0
  205. data/test/serializers/serialization_test.rb +55 -0
  206. data/test/serializers/serializer_for_test.rb +136 -0
  207. data/test/serializers/serializer_for_with_namespace_test.rb +88 -0
  208. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  209. data/test/support/isolated_unit.rb +82 -0
  210. data/test/support/rails5_shims.rb +53 -0
  211. data/test/support/rails_app.rb +36 -0
  212. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  213. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
  214. data/test/support/schemas/custom/show.json +7 -0
  215. data/test/support/schemas/hyper_schema.json +93 -0
  216. data/test/support/schemas/render_using_json_api.json +43 -0
  217. data/test/support/schemas/simple_json_pointers.json +10 -0
  218. data/test/support/serialization_testing.rb +71 -0
  219. data/test/test_helper.rb +58 -0
  220. metadata +602 -0
@@ -0,0 +1,80 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModelSerializers
4
+ module Adapter
5
+ class JsonApi
6
+ class HasOneTest < ActiveSupport::TestCase
7
+ def setup
8
+ @author = Author.new(id: 1, name: 'Steve K.')
9
+ @bio = Bio.new(id: 43, content: 'AMS Contributor')
10
+ @author.bio = @bio
11
+ @bio.author = @author
12
+ @post = Post.new(id: 42, title: 'New Post', body: 'Body')
13
+ @anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!')
14
+ @comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
15
+ @post.comments = [@comment]
16
+ @anonymous_post.comments = []
17
+ @comment.post = @post
18
+ @comment.author = nil
19
+ @post.author = @author
20
+ @anonymous_post.author = nil
21
+ @blog = Blog.new(id: 1, name: 'My Blog!!')
22
+ @blog.writer = @author
23
+ @blog.articles = [@post, @anonymous_post]
24
+ @author.posts = []
25
+ @author.roles = []
26
+
27
+ @virtual_value = VirtualValue.new(id: 1)
28
+
29
+ @serializer = AuthorSerializer.new(@author)
30
+ @adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer, include: [:bio, :posts])
31
+ end
32
+
33
+ def test_includes_bio_id
34
+ expected = { data: { type: 'bios', id: '43' } }
35
+
36
+ assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:bio])
37
+ end
38
+
39
+ def test_includes_linked_bio
40
+ @adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer, include: [:bio])
41
+
42
+ expected = [
43
+ {
44
+ id: '43',
45
+ type: 'bios',
46
+ attributes: {
47
+ content: 'AMS Contributor',
48
+ rating: nil
49
+ },
50
+ relationships: {
51
+ author: { data: { type: 'authors', id: '1' } }
52
+ }
53
+ }
54
+ ]
55
+
56
+ assert_equal(expected, @adapter.serializable_hash[:included])
57
+ end
58
+
59
+ def test_has_one_with_virtual_value
60
+ serializer = VirtualValueSerializer.new(@virtual_value)
61
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
62
+
63
+ expected = {
64
+ data: {
65
+ id: '1',
66
+ type: 'virtual-values',
67
+ relationships: {
68
+ maker: { data: { type: 'makers', id: '1' } },
69
+ reviews: { data: [{ type: 'reviews', id: '1' },
70
+ { type: 'reviews', id: '2' }] }
71
+ }
72
+ }
73
+ }
74
+
75
+ assert_equal(expected, adapter.serializable_hash)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,168 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ module Adapter
6
+ class JsonApi
7
+ class IncludeParamTest < ActiveSupport::TestCase
8
+ IncludeParamAuthor = Class.new(::Model) do
9
+ associations :tags, :posts
10
+ end
11
+
12
+ class CustomCommentLoader
13
+ def all
14
+ [{ foo: 'bar' }]
15
+ end
16
+ end
17
+
18
+ class TagSerializer < ActiveModel::Serializer
19
+ attributes :id, :name
20
+ end
21
+
22
+ class IncludeParamAuthorSerializer < ActiveModel::Serializer
23
+ class_attribute :comment_loader
24
+
25
+ has_many :tags, serializer: TagSerializer do
26
+ link :self, '//example.com/link_author/relationships/tags'
27
+ include_data :if_sideloaded
28
+ end
29
+
30
+ has_many :unlinked_tags, serializer: TagSerializer do
31
+ include_data :if_sideloaded
32
+ end
33
+
34
+ has_many :posts, serializer: PostWithTagsSerializer do
35
+ include_data :if_sideloaded
36
+ end
37
+ has_many :locations do
38
+ include_data :if_sideloaded
39
+ end
40
+ has_many :comments do
41
+ include_data :if_sideloaded
42
+ IncludeParamAuthorSerializer.comment_loader.all
43
+ end
44
+ end
45
+
46
+ def setup
47
+ IncludeParamAuthorSerializer.comment_loader = Class.new(CustomCommentLoader).new
48
+ @tag = Tag.new(id: 1337, name: 'mytag')
49
+ @author = IncludeParamAuthor.new(
50
+ id: 1337,
51
+ tags: [@tag]
52
+ )
53
+ end
54
+
55
+ def test_relationship_not_loaded_when_not_included
56
+ expected = {
57
+ links: {
58
+ self: '//example.com/link_author/relationships/tags'
59
+ }
60
+ }
61
+
62
+ @author.define_singleton_method(:read_attribute_for_serialization) do |attr|
63
+ fail 'should not be called' if attr == :tags
64
+ super(attr)
65
+ end
66
+
67
+ assert_relationship(:tags, expected)
68
+ end
69
+
70
+ def test_relationship_included
71
+ expected = {
72
+ data: [
73
+ {
74
+ id: '1337',
75
+ type: 'tags'
76
+ }
77
+ ],
78
+ links: {
79
+ self: '//example.com/link_author/relationships/tags'
80
+ }
81
+ }
82
+
83
+ assert_relationship(:tags, expected, include: :tags)
84
+ end
85
+
86
+ def test_sideloads_included
87
+ expected = [
88
+ {
89
+ id: '1337',
90
+ type: 'tags',
91
+ attributes: { name: 'mytag' }
92
+ }
93
+ ]
94
+ hash = result(include: :tags)
95
+ assert_equal(expected, hash[:included])
96
+ end
97
+
98
+ def test_nested_relationship
99
+ expected = {
100
+ data: [
101
+ {
102
+ id: '1337',
103
+ type: 'tags'
104
+ }
105
+ ],
106
+ links: {
107
+ self: '//example.com/link_author/relationships/tags'
108
+ }
109
+ }
110
+
111
+ expected_no_data = {
112
+ links: {
113
+ self: '//example.com/link_author/relationships/tags'
114
+ }
115
+ }
116
+
117
+ assert_relationship(:tags, expected, include: [:tags, { posts: :tags }])
118
+
119
+ @author.define_singleton_method(:read_attribute_for_serialization) do |attr|
120
+ fail 'should not be called' if attr == :tags
121
+ super(attr)
122
+ end
123
+
124
+ assert_relationship(:tags, expected_no_data, include: { posts: :tags })
125
+ end
126
+
127
+ def test_include_params_with_no_block
128
+ @author.define_singleton_method(:read_attribute_for_serialization) do |attr|
129
+ fail 'should not be called' if attr == :locations
130
+ super(attr)
131
+ end
132
+
133
+ expected = { meta: {} }
134
+
135
+ assert_relationship(:locations, expected)
136
+ end
137
+
138
+ def test_block_relationship
139
+ expected = {
140
+ data: [
141
+ { 'foo' => 'bar' }
142
+ ]
143
+ }
144
+
145
+ assert_relationship(:comments, expected, include: [:comments])
146
+ end
147
+
148
+ def test_node_not_included_when_no_link
149
+ expected = nil
150
+ assert_relationship(:unlinked_tags, expected)
151
+ end
152
+
153
+ private
154
+
155
+ def result(opts)
156
+ opts = { adapter: :json_api }.merge(opts)
157
+ serializable(@author, opts).serializable_hash
158
+ end
159
+
160
+ def assert_relationship(relationship_name, expected, opts = {})
161
+ hash = result(opts)
162
+ assert_equal(expected, hash[:data][:relationships][relationship_name])
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModelSerializers
4
+ module Adapter
5
+ class JsonApiTest < ActiveSupport::TestCase
6
+ def setup
7
+ ActionController::Base.cache_store.clear
8
+ @author = Author.new(id: 1, name: 'Steve K.')
9
+ @post = Post.new(id: 1, title: 'New Post', body: 'Body')
10
+ @first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
11
+ @second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
12
+ @post.comments = [@first_comment, @second_comment]
13
+ @first_comment.post = @post
14
+ @second_comment.post = @post
15
+ @post.author = @author
16
+ @blog = Blog.new(id: 1, name: 'My Blog!!')
17
+ @post.blog = @blog
18
+ end
19
+
20
+ def test_custom_keys
21
+ serializer = PostWithCustomKeysSerializer.new(@post)
22
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
23
+
24
+ assert_equal({
25
+ reviews: { data: [{ type: 'comments', id: '1' },
26
+ { type: 'comments', id: '2' }] },
27
+ writer: { data: { type: 'authors', id: '1' } },
28
+ site: { data: { type: 'blogs', id: '1' } }
29
+ }, adapter.serializable_hash[:data][:relationships])
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,413 @@
1
+ require 'test_helper'
2
+
3
+ class NestedPost < ::Model; associations :nested_posts end
4
+ class NestedPostSerializer < ActiveModel::Serializer
5
+ has_many :nested_posts
6
+ end
7
+ module ActiveModelSerializers
8
+ module Adapter
9
+ class JsonApi
10
+ class LinkedTest < ActiveSupport::TestCase
11
+ def setup
12
+ @author1 = Author.new(id: 1, name: 'Steve K.')
13
+ @author2 = Author.new(id: 2, name: 'Tenderlove')
14
+ @bio1 = Bio.new(id: 1, content: 'AMS Contributor')
15
+ @bio2 = Bio.new(id: 2, content: 'Rails Contributor')
16
+ @first_post = Post.new(id: 10, title: 'Hello!!', body: 'Hello, world!!')
17
+ @second_post = Post.new(id: 20, title: 'New Post', body: 'Body')
18
+ @third_post = Post.new(id: 30, title: 'Yet Another Post', body: 'Body')
19
+ @blog = Blog.new(name: 'AMS Blog')
20
+ @first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
21
+ @second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
22
+ @first_post.blog = @blog
23
+ @second_post.blog = @blog
24
+ @third_post.blog = nil
25
+ @first_post.comments = [@first_comment, @second_comment]
26
+ @second_post.comments = []
27
+ @third_post.comments = []
28
+ @first_post.author = @author1
29
+ @second_post.author = @author2
30
+ @third_post.author = @author1
31
+ @first_comment.post = @first_post
32
+ @first_comment.author = nil
33
+ @second_comment.post = @first_post
34
+ @second_comment.author = nil
35
+ @author1.posts = [@first_post, @third_post]
36
+ @author1.bio = @bio1
37
+ @author1.roles = []
38
+ @author2.posts = [@second_post]
39
+ @author2.bio = @bio2
40
+ @author2.roles = []
41
+ @bio1.author = @author1
42
+ @bio2.author = @author2
43
+ end
44
+
45
+ def test_include_multiple_posts_and_linked_array
46
+ serializer = ActiveModel::Serializer::CollectionSerializer.new([@first_post, @second_post])
47
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(
48
+ serializer,
49
+ include: [:comments, author: [:bio]]
50
+ )
51
+ alt_adapter = ActiveModelSerializers::Adapter::JsonApi.new(
52
+ serializer,
53
+ include: [:comments, author: [:bio]]
54
+ )
55
+
56
+ expected = {
57
+ data: [
58
+ {
59
+ id: '10',
60
+ type: 'posts',
61
+ attributes: {
62
+ title: 'Hello!!',
63
+ body: 'Hello, world!!'
64
+ },
65
+ relationships: {
66
+ comments: { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] },
67
+ blog: { data: { type: 'blogs', id: '999' } },
68
+ author: { data: { type: 'authors', id: '1' } }
69
+ }
70
+ },
71
+ {
72
+ id: '20',
73
+ type: 'posts',
74
+ attributes: {
75
+ title: 'New Post',
76
+ body: 'Body'
77
+ },
78
+ relationships: {
79
+ comments: { data: [] },
80
+ blog: { data: { type: 'blogs', id: '999' } },
81
+ author: { data: { type: 'authors', id: '2' } }
82
+ }
83
+ }
84
+ ],
85
+ included: [
86
+ {
87
+ id: '1',
88
+ type: 'comments',
89
+ attributes: {
90
+ body: 'ZOMG A COMMENT'
91
+ },
92
+ relationships: {
93
+ post: { data: { type: 'posts', id: '10' } },
94
+ author: { data: nil }
95
+ }
96
+ }, {
97
+ id: '2',
98
+ type: 'comments',
99
+ attributes: {
100
+ body: 'ZOMG ANOTHER COMMENT'
101
+ },
102
+ relationships: {
103
+ post: { data: { type: 'posts', id: '10' } },
104
+ author: { data: nil }
105
+ }
106
+ }, {
107
+ id: '1',
108
+ type: 'authors',
109
+ attributes: {
110
+ name: 'Steve K.'
111
+ },
112
+ relationships: {
113
+ posts: { data: [{ type: 'posts', id: '10' }, { type: 'posts', id: '30' }] },
114
+ roles: { data: [] },
115
+ bio: { data: { type: 'bios', id: '1' } }
116
+ }
117
+ }, {
118
+ id: '1',
119
+ type: 'bios',
120
+ attributes: {
121
+ content: 'AMS Contributor',
122
+ rating: nil
123
+ },
124
+ relationships: {
125
+ author: { data: { type: 'authors', id: '1' } }
126
+ }
127
+ }, {
128
+ id: '2',
129
+ type: 'authors',
130
+ attributes: {
131
+ name: 'Tenderlove'
132
+ },
133
+ relationships: {
134
+ posts: { data: [{ type: 'posts', id: '20' }] },
135
+ roles: { data: [] },
136
+ bio: { data: { type: 'bios', id: '2' } }
137
+ }
138
+ }, {
139
+ id: '2',
140
+ type: 'bios',
141
+ attributes: {
142
+ rating: nil,
143
+ content: 'Rails Contributor'
144
+ },
145
+ relationships: {
146
+ author: { data: { type: 'authors', id: '2' } }
147
+ }
148
+ }
149
+ ]
150
+ }
151
+ assert_equal expected, adapter.serializable_hash
152
+ assert_equal expected, alt_adapter.serializable_hash
153
+ end
154
+
155
+ def test_include_multiple_posts_and_linked
156
+ serializer = BioSerializer.new @bio1
157
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(
158
+ serializer,
159
+ include: [author: [:posts]]
160
+ )
161
+ alt_adapter = ActiveModelSerializers::Adapter::JsonApi.new(
162
+ serializer,
163
+ include: [author: [:posts]]
164
+ )
165
+
166
+ expected = [
167
+ {
168
+ id: '1',
169
+ type: 'authors',
170
+ attributes: {
171
+ name: 'Steve K.'
172
+ },
173
+ relationships: {
174
+ posts: { data: [{ type: 'posts', id: '10' }, { type: 'posts', id: '30' }] },
175
+ roles: { data: [] },
176
+ bio: { data: { type: 'bios', id: '1' } }
177
+ }
178
+ }, {
179
+ id: '10',
180
+ type: 'posts',
181
+ attributes: {
182
+ title: 'Hello!!',
183
+ body: 'Hello, world!!'
184
+ },
185
+ relationships: {
186
+ comments: { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] },
187
+ blog: { data: { type: 'blogs', id: '999' } },
188
+ author: { data: { type: 'authors', id: '1' } }
189
+ }
190
+ }, {
191
+ id: '30',
192
+ type: 'posts',
193
+ attributes: {
194
+ title: 'Yet Another Post',
195
+ body: 'Body'
196
+ },
197
+ relationships: {
198
+ comments: { data: [] },
199
+ blog: { data: { type: 'blogs', id: '999' } },
200
+ author: { data: { type: 'authors', id: '1' } }
201
+ }
202
+ }
203
+ ]
204
+
205
+ assert_equal expected, adapter.serializable_hash[:included]
206
+ assert_equal expected, alt_adapter.serializable_hash[:included]
207
+ end
208
+
209
+ def test_underscore_model_namespace_for_linked_resource_type
210
+ spammy_post = Post.new(id: 123)
211
+ spammy_post.related = [Spam::UnrelatedLink.new(id: 456)]
212
+ serializer = SpammyPostSerializer.new(spammy_post)
213
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
214
+ relationships = adapter.serializable_hash[:data][:relationships]
215
+ expected = {
216
+ related: {
217
+ data: [{
218
+ type: 'spam-unrelated-links',
219
+ id: '456'
220
+ }]
221
+ }
222
+ }
223
+ assert_equal expected, relationships
224
+ end
225
+
226
+ def test_underscore_model_namespace_with_namespace_separator_for_linked_resource_type
227
+ spammy_post = Post.new(id: 123)
228
+ spammy_post.related = [Spam::UnrelatedLink.new(id: 456)]
229
+ serializer = SpammyPostSerializer.new(spammy_post)
230
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
231
+ relationships = with_namespace_separator '--' do
232
+ adapter.serializable_hash[:data][:relationships]
233
+ end
234
+ expected = {
235
+ related: {
236
+ data: [{
237
+ type: 'spam--unrelated-links',
238
+ id: '456'
239
+ }]
240
+ }
241
+ }
242
+ assert_equal expected, relationships
243
+ end
244
+
245
+ def test_multiple_references_to_same_resource
246
+ serializer = ActiveModel::Serializer::CollectionSerializer.new([@first_comment, @second_comment])
247
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(
248
+ serializer,
249
+ include: [:post]
250
+ )
251
+
252
+ expected = [
253
+ {
254
+ id: '10',
255
+ type: 'posts',
256
+ attributes: {
257
+ title: 'Hello!!',
258
+ body: 'Hello, world!!'
259
+ },
260
+ relationships: {
261
+ comments: {
262
+ data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }]
263
+ },
264
+ blog: {
265
+ data: { type: 'blogs', id: '999' }
266
+ },
267
+ author: {
268
+ data: { type: 'authors', id: '1' }
269
+ }
270
+ }
271
+ }
272
+ ]
273
+
274
+ assert_equal expected, adapter.serializable_hash[:included]
275
+ end
276
+
277
+ def test_nil_link_with_specified_serializer
278
+ @first_post.author = nil
279
+ serializer = PostPreviewSerializer.new(@first_post)
280
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(
281
+ serializer,
282
+ include: [:author]
283
+ )
284
+
285
+ expected = {
286
+ data: {
287
+ id: '10',
288
+ type: 'posts',
289
+ attributes: {
290
+ title: 'Hello!!',
291
+ body: 'Hello, world!!'
292
+ },
293
+ relationships: {
294
+ comments: { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] },
295
+ author: { data: nil }
296
+ }
297
+ }
298
+ }
299
+ assert_equal expected, adapter.serializable_hash
300
+ end
301
+ end
302
+
303
+ class NoDuplicatesTest < ActiveSupport::TestCase
304
+ class Post < ::Model; associations :author end
305
+ class Author < ::Model; associations :posts, :roles, :bio end
306
+
307
+ class PostSerializer < ActiveModel::Serializer
308
+ type 'posts'
309
+ belongs_to :author
310
+ end
311
+
312
+ class AuthorSerializer < ActiveModel::Serializer
313
+ type 'authors'
314
+ has_many :posts
315
+ end
316
+
317
+ def setup
318
+ @author = Author.new(id: 1, posts: [], roles: [], bio: nil)
319
+ @post1 = Post.new(id: 1, author: @author)
320
+ @post2 = Post.new(id: 2, author: @author)
321
+ @author.posts << @post1
322
+ @author.posts << @post2
323
+
324
+ @nestedpost1 = NestedPost.new(id: 1, nested_posts: [])
325
+ @nestedpost2 = NestedPost.new(id: 2, nested_posts: [])
326
+ @nestedpost1.nested_posts << @nestedpost1
327
+ @nestedpost1.nested_posts << @nestedpost2
328
+ @nestedpost2.nested_posts << @nestedpost1
329
+ @nestedpost2.nested_posts << @nestedpost2
330
+ end
331
+
332
+ def test_no_duplicates
333
+ hash = ActiveModelSerializers::SerializableResource.new(@post1, adapter: :json_api,
334
+ include: '*.*')
335
+ .serializable_hash
336
+ expected = [
337
+ {
338
+ type: 'authors', id: '1',
339
+ relationships: {
340
+ posts: {
341
+ data: [
342
+ { type: 'posts', id: '1' },
343
+ { type: 'posts', id: '2' }
344
+ ]
345
+ }
346
+ }
347
+ },
348
+ {
349
+ type: 'posts', id: '2',
350
+ relationships: {
351
+ author: {
352
+ data: { type: 'authors', id: '1' }
353
+ }
354
+ }
355
+ }
356
+ ]
357
+ assert_equal(expected, hash[:included])
358
+ end
359
+
360
+ def test_no_duplicates_collection
361
+ hash = ActiveModelSerializers::SerializableResource.new(
362
+ [@post1, @post2],
363
+ adapter: :json_api,
364
+ include: '*.*'
365
+ ).serializable_hash
366
+ expected = [
367
+ {
368
+ type: 'authors', id: '1',
369
+ relationships: {
370
+ posts: {
371
+ data: [
372
+ { type: 'posts', id: '1' },
373
+ { type: 'posts', id: '2' }
374
+ ]
375
+ }
376
+ }
377
+ }
378
+ ]
379
+ assert_equal(expected, hash[:included])
380
+ end
381
+
382
+ def test_no_duplicates_global
383
+ hash = ActiveModelSerializers::SerializableResource.new(
384
+ @nestedpost1,
385
+ adapter: :json_api,
386
+ include: '*'
387
+ ).serializable_hash
388
+ expected = [
389
+ type: 'nested-posts', id: '2',
390
+ relationships: {
391
+ :"nested-posts" => {
392
+ data: [
393
+ { type: 'nested-posts', id: '1' },
394
+ { type: 'nested-posts', id: '2' }
395
+ ]
396
+ }
397
+ }
398
+ ]
399
+ assert_equal(expected, hash[:included])
400
+ end
401
+
402
+ def test_no_duplicates_collection_global
403
+ hash = ActiveModelSerializers::SerializableResource.new(
404
+ [@nestedpost1, @nestedpost2],
405
+ adapter: :json_api,
406
+ include: '*'
407
+ ).serializable_hash
408
+ assert_nil(hash[:included])
409
+ end
410
+ end
411
+ end
412
+ end
413
+ end