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,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ module ActionController
6
+ module Serialization
7
+ class JsonApi
8
+ class DeserializationTest < ActionController::TestCase
9
+ class DeserializationTestController < ActionController::Base
10
+ def render_parsed_payload
11
+ parsed_hash = ActiveModelSerializers::Deserialization.jsonapi_parse(params)
12
+ render json: parsed_hash
13
+ end
14
+
15
+ def render_polymorphic_parsed_payload
16
+ parsed_hash = ActiveModelSerializers::Deserialization.jsonapi_parse(
17
+ params,
18
+ polymorphic: [:restriction_for, :restricted_to]
19
+ )
20
+ render json: parsed_hash
21
+ end
22
+ end
23
+
24
+ tests DeserializationTestController
25
+
26
+ def test_deserialization_of_relationship_only_object
27
+ hash = {
28
+ 'data' => {
29
+ 'type' => 'restraints',
30
+ 'relationships' => {
31
+ 'restriction_for' => {
32
+ 'data' => {
33
+ 'type' => 'discounts',
34
+ 'id' => '67'
35
+ }
36
+ },
37
+ 'restricted_to' => {
38
+ 'data' => nil
39
+ }
40
+ }
41
+ },
42
+ 'restraint' => {}
43
+ }
44
+
45
+ post :render_polymorphic_parsed_payload, params: hash
46
+
47
+ response = JSON.parse(@response.body)
48
+ expected = {
49
+ 'restriction_for_id' => '67',
50
+ 'restriction_for_type' => 'Discount',
51
+ 'restricted_to_id' => nil,
52
+ 'restricted_to_type' => nil
53
+ }
54
+
55
+ assert_equal(expected, response)
56
+ end
57
+
58
+ def test_deserialization
59
+ hash = {
60
+ 'data' => {
61
+ 'type' => 'photos',
62
+ 'id' => 'zorglub',
63
+ 'attributes' => {
64
+ 'title' => 'Ember Hamster',
65
+ 'src' => 'http://example.com/images/productivity.png',
66
+ 'image-width' => '200',
67
+ 'imageHeight' => '200',
68
+ 'ImageSize' => '1024'
69
+ },
70
+ 'relationships' => {
71
+ 'author' => {
72
+ 'data' => nil
73
+ },
74
+ 'photographer' => {
75
+ 'data' => { 'type' => 'people', 'id' => '9' }
76
+ },
77
+ 'comments' => {
78
+ 'data' => [
79
+ { 'type' => 'comments', 'id' => '1' },
80
+ { 'type' => 'comments', 'id' => '2' }
81
+ ]
82
+ },
83
+ 'related-images' => {
84
+ 'data' => [
85
+ { 'type' => 'image', 'id' => '7' },
86
+ { 'type' => 'image', 'id' => '8' }
87
+ ]
88
+ }
89
+ }
90
+ }
91
+ }
92
+
93
+ post :render_parsed_payload, params: hash
94
+
95
+ response = JSON.parse(@response.body)
96
+ expected = {
97
+ 'id' => 'zorglub',
98
+ 'title' => 'Ember Hamster',
99
+ 'src' => 'http://example.com/images/productivity.png',
100
+ 'image_width' => '200',
101
+ 'image_height' => '200',
102
+ 'image_size' => '1024',
103
+ 'author_id' => nil,
104
+ 'photographer_id' => '9',
105
+ 'comment_ids' => %w(1 2),
106
+ 'related_image_ids' => %w(7 8)
107
+ }
108
+
109
+ assert_equal(expected, response)
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ module ActionController
6
+ module Serialization
7
+ class JsonApi
8
+ class ErrorsTest < ActionController::TestCase
9
+ def test_active_model_with_multiple_errors
10
+ get :render_resource_with_errors
11
+
12
+ expected_errors_object = {
13
+ errors: [
14
+ { source: { pointer: '/data/attributes/name' }, detail: 'cannot be nil' },
15
+ { source: { pointer: '/data/attributes/name' }, detail: 'must be longer' },
16
+ { source: { pointer: '/data/attributes/id' }, detail: 'must be a uuid' }
17
+ ]
18
+ }.to_json
19
+ assert_equal json_response_body.to_json, expected_errors_object
20
+ end
21
+
22
+ def json_response_body
23
+ JSON.load(@response.body)
24
+ end
25
+
26
+ class ErrorsTestController < ActionController::Base
27
+ def render_resource_with_errors
28
+ resource = Profile.new(name: 'Name 1',
29
+ description: 'Description 1',
30
+ comments: 'Comments 1')
31
+ resource.errors.add(:name, 'cannot be nil')
32
+ resource.errors.add(:name, 'must be longer')
33
+ resource.errors.add(:id, 'must be a uuid')
34
+ render json: resource, adapter: :json_api, serializer: ActiveModel::Serializer::ErrorSerializer
35
+ end
36
+ end
37
+
38
+ tests ErrorsTestController
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ module ActionController
6
+ module Serialization
7
+ class JsonApi
8
+ class FieldsTest < ActionController::TestCase
9
+ class FieldsTestController < ActionController::Base
10
+ class AuthorWithName < Author
11
+ attributes :first_name, :last_name
12
+ end
13
+ class AuthorWithNameSerializer < AuthorSerializer
14
+ type 'authors'
15
+ end
16
+ class PostWithPublishAt < Post
17
+ attributes :publish_at
18
+ end
19
+ class PostWithPublishAtSerializer < ActiveModel::Serializer
20
+ type 'posts'
21
+ attributes :title, :body, :publish_at
22
+ belongs_to :author
23
+ has_many :comments
24
+ end
25
+
26
+ def setup_post
27
+ ActionController::Base.cache_store.clear
28
+ @author = AuthorWithName.new(id: 1, first_name: 'Bob', last_name: 'Jones')
29
+ @comment1 = Comment.new(id: 7, body: 'cool', author: @author)
30
+ @comment2 = Comment.new(id: 12, body: 'awesome', author: @author)
31
+ @post = PostWithPublishAt.new(id: 1337, title: 'Title 1', body: 'Body 1',
32
+ author: @author, comments: [@comment1, @comment2],
33
+ publish_at: '2020-03-16T03:55:25.291Z')
34
+ @comment1.post = @post
35
+ @comment2.post = @post
36
+ end
37
+
38
+ def render_fields_works_on_relationships
39
+ setup_post
40
+ render json: @post, serializer: PostWithPublishAtSerializer, adapter: :json_api, fields: { posts: [:author] }
41
+ end
42
+ end
43
+
44
+ tests FieldsTestController
45
+
46
+ test 'fields works on relationships' do
47
+ get :render_fields_works_on_relationships
48
+ response = JSON.parse(@response.body)
49
+ expected = {
50
+ 'data' => {
51
+ 'id' => '1337',
52
+ 'type' => 'posts',
53
+ 'relationships' => {
54
+ 'author' => {
55
+ 'data' => {
56
+ 'id' => '1',
57
+ 'type' => 'authors'
58
+ }
59
+ }
60
+ }
61
+ }
62
+ }
63
+ assert_equal expected, response
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,204 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ module ActionController
6
+ module Serialization
7
+ class JsonApi
8
+ class LinkedTest < ActionDispatch::IntegrationTest
9
+ class LinkedTestController < ActionController::Base
10
+ def setup_post
11
+ ActionController::Base.cache_store.clear
12
+ @role1 = Role.new(id: 1, name: 'admin')
13
+ @role2 = Role.new(id: 2, name: 'colab')
14
+ @author = Author.new(id: 1, name: 'Steve K.')
15
+ @author.posts = []
16
+ @author.bio = nil
17
+ @author.roles = [@role1, @role2]
18
+ @role1.author = @author
19
+ @role2.author = @author
20
+ @author2 = Author.new(id: 2, name: 'Anonymous')
21
+ @author2.posts = []
22
+ @author2.bio = nil
23
+ @author2.roles = []
24
+ @post = Post.new(id: 1, title: 'New Post', body: 'Body')
25
+ @first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
26
+ @second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
27
+ @post.comments = [@first_comment, @second_comment]
28
+ @post.author = @author
29
+ @first_comment.post = @post
30
+ @first_comment.author = @author2
31
+ @second_comment.post = @post
32
+ @second_comment.author = nil
33
+ @post2 = Post.new(id: 2, title: 'Another Post', body: 'Body')
34
+ @post2.author = @author
35
+ @post2.comments = []
36
+ @blog = Blog.new(id: 1, name: 'My Blog!!')
37
+ @post.blog = @blog
38
+ @post2.blog = @blog
39
+ end
40
+
41
+ def render_resource_without_include
42
+ setup_post
43
+ render json: @post
44
+ end
45
+
46
+ def render_resource_with_include
47
+ setup_post
48
+ render json: @post, adapter: :json_api, include: [:author]
49
+ end
50
+
51
+ def render_resource_with_include_of_custom_key_by_original
52
+ setup_post
53
+ render json: @post, adapter: :json_api, include: [:reviews], serializer: PostWithCustomKeysSerializer
54
+ end
55
+
56
+ def render_resource_with_nested_include
57
+ setup_post
58
+ render json: @post, adapter: :json_api, include: [comments: [:author]]
59
+ end
60
+
61
+ def render_resource_with_nested_has_many_include_wildcard
62
+ setup_post
63
+ render json: @post, adapter: :json_api, include: 'author.*'
64
+ end
65
+
66
+ def render_resource_with_missing_nested_has_many_include
67
+ setup_post
68
+ @post.author = @author2 # author2 has no roles.
69
+ render json: @post, adapter: :json_api, include: [author: [:roles]]
70
+ end
71
+
72
+ def render_collection_with_missing_nested_has_many_include
73
+ setup_post
74
+ @post.author = @author2
75
+ render json: [@post, @post2], adapter: :json_api, include: [author: [:roles]]
76
+ end
77
+
78
+ def render_collection_without_include
79
+ setup_post
80
+ render json: [@post], adapter: :json_api
81
+ end
82
+
83
+ def render_collection_with_include
84
+ setup_post
85
+ render json: [@post], adapter: :json_api, include: 'author, comments'
86
+ end
87
+ end
88
+
89
+ setup do
90
+ @routes = Rails.application.routes.draw do
91
+ ActiveSupport::Deprecation.silence do
92
+ match ':action', to: LinkedTestController, via: [:get, :post]
93
+ end
94
+ end
95
+ end
96
+
97
+ def test_render_resource_without_include
98
+ get '/render_resource_without_include'
99
+ response = JSON.parse(@response.body)
100
+ refute response.key? 'included'
101
+ end
102
+
103
+ def test_render_resource_with_include
104
+ get '/render_resource_with_include'
105
+ response = JSON.parse(@response.body)
106
+ assert response.key? 'included'
107
+ assert_equal 1, response['included'].size
108
+ assert_equal 'Steve K.', response['included'].first['attributes']['name']
109
+ end
110
+
111
+ def test_render_resource_with_nested_has_many_include
112
+ get '/render_resource_with_nested_has_many_include_wildcard'
113
+ response = JSON.parse(@response.body)
114
+ expected_linked = [
115
+ {
116
+ 'id' => '1',
117
+ 'type' => 'authors',
118
+ 'attributes' => {
119
+ 'name' => 'Steve K.'
120
+ },
121
+ 'relationships' => {
122
+ 'posts' => { 'data' => [] },
123
+ 'roles' => { 'data' => [{ 'type' => 'roles', 'id' => '1' }, { 'type' => 'roles', 'id' => '2' }] },
124
+ 'bio' => { 'data' => nil }
125
+ }
126
+ }, {
127
+ 'id' => '1',
128
+ 'type' => 'roles',
129
+ 'attributes' => {
130
+ 'name' => 'admin',
131
+ 'description' => nil,
132
+ 'slug' => 'admin-1'
133
+ },
134
+ 'relationships' => {
135
+ 'author' => { 'data' => { 'type' => 'authors', 'id' => '1' } }
136
+ }
137
+ }, {
138
+ 'id' => '2',
139
+ 'type' => 'roles',
140
+ 'attributes' => {
141
+ 'name' => 'colab',
142
+ 'description' => nil,
143
+ 'slug' => 'colab-2'
144
+ },
145
+ 'relationships' => {
146
+ 'author' => { 'data' => { 'type' => 'authors', 'id' => '1' } }
147
+ }
148
+ }
149
+ ]
150
+ assert_equal expected_linked, response['included']
151
+ end
152
+
153
+ def test_render_resource_with_include_of_custom_key_by_original
154
+ get '/render_resource_with_include_of_custom_key_by_original'
155
+ response = JSON.parse(@response.body)
156
+ assert response.key? 'included'
157
+
158
+ relationships = response['data']['relationships']
159
+
160
+ assert_includes relationships, 'reviews'
161
+ assert_includes relationships, 'writer'
162
+ assert_includes relationships, 'site'
163
+ end
164
+
165
+ def test_render_resource_with_nested_include
166
+ get '/render_resource_with_nested_include'
167
+ response = JSON.parse(@response.body)
168
+ assert response.key? 'included'
169
+ assert_equal 3, response['included'].size
170
+ end
171
+
172
+ def test_render_collection_without_include
173
+ get '/render_collection_without_include'
174
+ response = JSON.parse(@response.body)
175
+ refute response.key? 'included'
176
+ end
177
+
178
+ def test_render_collection_with_include
179
+ get '/render_collection_with_include'
180
+ response = JSON.parse(@response.body)
181
+ assert response.key? 'included'
182
+ end
183
+
184
+ def test_render_resource_with_nested_attributes_even_when_missing_associations
185
+ get '/render_resource_with_missing_nested_has_many_include'
186
+ response = JSON.parse(@response.body)
187
+ assert response.key? 'included'
188
+ refute include_type?(response['included'], 'roles')
189
+ end
190
+
191
+ def test_render_collection_with_missing_nested_has_many_include
192
+ get '/render_collection_with_missing_nested_has_many_include'
193
+ response = JSON.parse(@response.body)
194
+ assert response.key? 'included'
195
+ assert include_type?(response['included'], 'roles')
196
+ end
197
+
198
+ def include_type?(collection, value)
199
+ collection.detect { |i| i['type'] == value }
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'will_paginate/array'
5
+ require 'kaminari'
6
+ require 'kaminari/hooks'
7
+ ::Kaminari::Hooks.init
8
+
9
+ module ActionController
10
+ module Serialization
11
+ class JsonApi
12
+ class PaginationTest < ActionController::TestCase
13
+ KAMINARI_URI = 'http://test.host/action_controller/serialization/json_api/pagination_test/pagination_test/render_pagination_using_kaminari'.freeze
14
+ WILL_PAGINATE_URI = 'http://test.host/action_controller/serialization/json_api/pagination_test/pagination_test/render_pagination_using_will_paginate'.freeze
15
+
16
+ class PaginationTestController < ActionController::Base
17
+ def setup
18
+ @array = [
19
+ Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1'),
20
+ Profile.new(name: 'Name 2', description: 'Description 2', comments: 'Comments 2'),
21
+ Profile.new(name: 'Name 3', description: 'Description 3', comments: 'Comments 3')
22
+ ]
23
+ end
24
+
25
+ def using_kaminari
26
+ setup
27
+ Kaminari.paginate_array(@array).page(params[:page][:number]).per(params[:page][:size])
28
+ end
29
+
30
+ def using_will_paginate
31
+ setup
32
+ @array.paginate(page: params[:page][:number], per_page: params[:page][:size])
33
+ end
34
+
35
+ def render_pagination_using_kaminari
36
+ render json: using_kaminari, adapter: :json_api
37
+ end
38
+
39
+ def render_pagination_using_will_paginate
40
+ render json: using_will_paginate, adapter: :json_api
41
+ end
42
+
43
+ def render_array_without_pagination_links
44
+ setup
45
+ render json: @array, adapter: :json_api
46
+ end
47
+ end
48
+
49
+ tests PaginationTestController
50
+
51
+ def test_render_pagination_links_with_will_paginate
52
+ expected_links = { 'self' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1",
53
+ 'first' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1",
54
+ 'prev' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1",
55
+ 'next' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1",
56
+ 'last' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1" }
57
+
58
+ get :render_pagination_using_will_paginate, params: { page: { number: 2, size: 1 } }
59
+ response = JSON.parse(@response.body)
60
+ assert_equal expected_links, response['links']
61
+ end
62
+
63
+ def test_render_only_first_last_and_next_pagination_links
64
+ expected_links = { 'self' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
65
+ 'first' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
66
+ 'prev' => nil,
67
+ 'next' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2",
68
+ 'last' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2" }
69
+ get :render_pagination_using_will_paginate, params: { page: { number: 1, size: 2 } }
70
+ response = JSON.parse(@response.body)
71
+ assert_equal expected_links, response['links']
72
+ end
73
+
74
+ def test_render_pagination_links_with_kaminari
75
+ expected_links = { 'self' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1",
76
+ 'first' => "#{KAMINARI_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1",
77
+ 'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1",
78
+ 'next' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1",
79
+ 'last' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1" }
80
+ get :render_pagination_using_kaminari, params: { page: { number: 2, size: 1 } }
81
+ response = JSON.parse(@response.body)
82
+ assert_equal expected_links, response['links']
83
+ end
84
+
85
+ def test_render_only_prev_first_and_last_pagination_links
86
+ expected_links = { 'self' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1",
87
+ 'first' => "#{KAMINARI_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1",
88
+ 'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1",
89
+ 'next' => nil,
90
+ 'last' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1" }
91
+ get :render_pagination_using_kaminari, params: { page: { number: 3, size: 1 } }
92
+ response = JSON.parse(@response.body)
93
+ assert_equal expected_links, response['links']
94
+ end
95
+
96
+ def test_render_only_first_last_and_next_pagination_links_with_additional_params
97
+ expected_links = { 'self' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2&teste=additional",
98
+ 'first' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2&teste=additional",
99
+ 'prev' => nil,
100
+ 'next' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2&teste=additional",
101
+ 'last' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2&teste=additional" }
102
+ get :render_pagination_using_will_paginate, params: { page: { number: 1, size: 2 }, teste: 'additional' }
103
+ response = JSON.parse(@response.body)
104
+ assert_equal expected_links, response['links']
105
+ end
106
+
107
+ def test_render_only_prev_first_and_last_pagination_links_with_additional_params
108
+ expected_links = { 'self' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1&teste=additional",
109
+ 'first' => "#{KAMINARI_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1&teste=additional",
110
+ 'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1&teste=additional",
111
+ 'next' => nil,
112
+ 'last' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1&teste=additional" }
113
+ get :render_pagination_using_kaminari, params: { page: { number: 3, size: 1 }, teste: 'additional' }
114
+ response = JSON.parse(@response.body)
115
+ assert_equal expected_links, response['links']
116
+ end
117
+
118
+ def test_array_without_pagination_links
119
+ get :render_array_without_pagination_links, params: { page: { number: 2, size: 1 } }
120
+ response = JSON.parse(@response.body)
121
+ refute response.key? 'links'
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end