active_model_serializers 0.10.0 → 0.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +6 -5
  3. data/.travis.yml +30 -21
  4. data/CHANGELOG.md +172 -2
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +23 -4
  7. data/README.md +166 -28
  8. data/Rakefile +3 -32
  9. data/active_model_serializers.gemspec +22 -25
  10. data/appveyor.yml +10 -6
  11. data/bin/rubocop +38 -0
  12. data/docs/README.md +2 -1
  13. data/docs/general/adapters.md +35 -11
  14. data/docs/general/caching.md +7 -1
  15. data/docs/general/configuration_options.md +86 -1
  16. data/docs/general/deserialization.md +1 -1
  17. data/docs/general/fields.md +31 -0
  18. data/docs/general/getting_started.md +1 -1
  19. data/docs/general/logging.md +7 -0
  20. data/docs/general/rendering.md +63 -25
  21. data/docs/general/serializers.md +125 -14
  22. data/docs/howto/add_pagination_links.md +16 -17
  23. data/docs/howto/add_relationship_links.md +140 -0
  24. data/docs/howto/add_root_key.md +11 -0
  25. data/docs/howto/grape_integration.md +42 -0
  26. data/docs/howto/outside_controller_use.md +12 -4
  27. data/docs/howto/passing_arbitrary_options.md +2 -2
  28. data/docs/howto/serialize_poro.md +46 -5
  29. data/docs/howto/test.md +2 -0
  30. data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
  31. data/docs/integrations/ember-and-json-api.md +67 -32
  32. data/docs/jsonapi/schema.md +1 -1
  33. data/lib/action_controller/serialization.rb +13 -3
  34. data/lib/active_model/serializer/adapter/base.rb +2 -0
  35. data/lib/active_model/serializer/array_serializer.rb +8 -5
  36. data/lib/active_model/serializer/association.rb +62 -10
  37. data/lib/active_model/serializer/belongs_to_reflection.rb +4 -3
  38. data/lib/active_model/serializer/collection_serializer.rb +39 -13
  39. data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +82 -115
  40. data/lib/active_model/serializer/error_serializer.rb +11 -7
  41. data/lib/active_model/serializer/errors_serializer.rb +25 -20
  42. data/lib/active_model/serializer/has_many_reflection.rb +3 -3
  43. data/lib/active_model/serializer/has_one_reflection.rb +1 -4
  44. data/lib/active_model/serializer/lazy_association.rb +95 -0
  45. data/lib/active_model/serializer/lint.rb +134 -130
  46. data/lib/active_model/serializer/reflection.rb +127 -67
  47. data/lib/active_model/serializer/version.rb +1 -1
  48. data/lib/active_model/serializer.rb +297 -79
  49. data/lib/active_model_serializers/adapter/attributes.rb +3 -66
  50. data/lib/active_model_serializers/adapter/base.rb +39 -39
  51. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +2 -2
  52. data/lib/active_model_serializers/adapter/json_api/link.rb +1 -1
  53. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +47 -21
  54. data/lib/active_model_serializers/adapter/json_api/relationship.rb +75 -23
  55. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +39 -10
  56. data/lib/active_model_serializers/adapter/json_api.rb +71 -57
  57. data/lib/active_model_serializers/adapter.rb +6 -0
  58. data/lib/active_model_serializers/deprecate.rb +1 -2
  59. data/lib/active_model_serializers/deserialization.rb +2 -0
  60. data/lib/active_model_serializers/lookup_chain.rb +80 -0
  61. data/lib/active_model_serializers/model.rb +109 -28
  62. data/lib/active_model_serializers/railtie.rb +3 -1
  63. data/lib/active_model_serializers/register_jsonapi_renderer.rb +44 -31
  64. data/lib/active_model_serializers/serializable_resource.rb +6 -5
  65. data/lib/active_model_serializers/serialization_context.rb +10 -3
  66. data/lib/active_model_serializers/test/schema.rb +2 -2
  67. data/lib/active_model_serializers.rb +16 -1
  68. data/lib/generators/rails/resource_override.rb +1 -1
  69. data/lib/generators/rails/serializer_generator.rb +4 -4
  70. data/lib/grape/active_model_serializers.rb +7 -5
  71. data/lib/grape/formatters/active_model_serializers.rb +19 -2
  72. data/lib/grape/helpers/active_model_serializers.rb +1 -0
  73. data/lib/tasks/rubocop.rake +53 -0
  74. data/test/action_controller/adapter_selector_test.rb +14 -5
  75. data/test/action_controller/explicit_serializer_test.rb +5 -4
  76. data/test/action_controller/json/include_test.rb +106 -27
  77. data/test/action_controller/json_api/deserialization_test.rb +1 -1
  78. data/test/action_controller/json_api/errors_test.rb +8 -9
  79. data/test/action_controller/json_api/fields_test.rb +66 -0
  80. data/test/action_controller/json_api/linked_test.rb +29 -24
  81. data/test/action_controller/json_api/pagination_test.rb +31 -23
  82. data/test/action_controller/json_api/transform_test.rb +11 -3
  83. data/test/action_controller/lookup_proc_test.rb +49 -0
  84. data/test/action_controller/namespace_lookup_test.rb +232 -0
  85. data/test/action_controller/serialization_scope_name_test.rb +12 -6
  86. data/test/action_controller/serialization_test.rb +12 -9
  87. data/test/active_model_serializers/json_pointer_test.rb +15 -13
  88. data/test/active_model_serializers/model_test.rb +137 -4
  89. data/test/active_model_serializers/railtie_test_isolated.rb +12 -7
  90. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +161 -0
  91. data/test/active_model_serializers/serialization_context_test_isolated.rb +23 -10
  92. data/test/active_model_serializers/test/schema_test.rb +3 -2
  93. data/test/adapter/attributes_test.rb +40 -0
  94. data/test/adapter/json/collection_test.rb +14 -0
  95. data/test/adapter/json/has_many_test.rb +10 -2
  96. data/test/adapter/json/transform_test.rb +15 -15
  97. data/test/adapter/json_api/collection_test.rb +4 -3
  98. data/test/adapter/json_api/errors_test.rb +17 -19
  99. data/test/adapter/json_api/fields_test.rb +12 -3
  100. data/test/adapter/json_api/has_many_test.rb +49 -20
  101. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +213 -0
  102. data/test/adapter/json_api/json_api_test.rb +5 -7
  103. data/test/adapter/json_api/linked_test.rb +33 -12
  104. data/test/adapter/json_api/links_test.rb +4 -2
  105. data/test/adapter/json_api/pagination_links_test.rb +53 -13
  106. data/test/adapter/json_api/parse_test.rb +1 -1
  107. data/test/adapter/json_api/relationship_test.rb +309 -73
  108. data/test/adapter/json_api/resource_meta_test.rb +3 -3
  109. data/test/adapter/json_api/transform_test.rb +263 -253
  110. data/test/adapter/json_api/type_test.rb +168 -36
  111. data/test/adapter/json_test.rb +8 -7
  112. data/test/adapter/null_test.rb +1 -2
  113. data/test/adapter/polymorphic_test.rb +52 -5
  114. data/test/adapter_test.rb +1 -1
  115. data/test/benchmark/app.rb +1 -1
  116. data/test/benchmark/benchmarking_support.rb +1 -1
  117. data/test/benchmark/bm_active_record.rb +81 -0
  118. data/test/benchmark/bm_adapter.rb +38 -0
  119. data/test/benchmark/bm_caching.rb +16 -16
  120. data/test/benchmark/bm_lookup_chain.rb +83 -0
  121. data/test/benchmark/bm_transform.rb +21 -10
  122. data/test/benchmark/controllers.rb +16 -17
  123. data/test/benchmark/fixtures.rb +72 -72
  124. data/test/cache_test.rb +235 -69
  125. data/test/collection_serializer_test.rb +31 -14
  126. data/test/fixtures/active_record.rb +45 -10
  127. data/test/fixtures/poro.rb +124 -181
  128. data/test/generators/serializer_generator_test.rb +23 -5
  129. data/test/grape_test.rb +170 -56
  130. data/test/lint_test.rb +1 -1
  131. data/test/logger_test.rb +13 -11
  132. data/test/serializable_resource_test.rb +18 -22
  133. data/test/serializers/association_macros_test.rb +3 -2
  134. data/test/serializers/associations_test.rb +222 -49
  135. data/test/serializers/attribute_test.rb +5 -3
  136. data/test/serializers/attributes_test.rb +1 -1
  137. data/test/serializers/caching_configuration_test_isolated.rb +6 -6
  138. data/test/serializers/fieldset_test.rb +1 -1
  139. data/test/serializers/meta_test.rb +12 -6
  140. data/test/serializers/options_test.rb +17 -6
  141. data/test/serializers/read_attribute_for_serialization_test.rb +3 -3
  142. data/test/serializers/reflection_test.rb +427 -0
  143. data/test/serializers/root_test.rb +1 -1
  144. data/test/serializers/serialization_test.rb +2 -2
  145. data/test/serializers/serializer_for_test.rb +12 -10
  146. data/test/serializers/serializer_for_with_namespace_test.rb +88 -0
  147. data/test/support/isolated_unit.rb +9 -4
  148. data/test/support/rails5_shims.rb +8 -2
  149. data/test/support/rails_app.rb +2 -9
  150. data/test/support/serialization_testing.rb +31 -5
  151. data/test/test_helper.rb +13 -0
  152. metadata +130 -71
  153. data/.rubocop_todo.yml +0 -167
  154. data/docs/ARCHITECTURE.md +0 -126
  155. data/lib/active_model/serializer/associations.rb +0 -100
  156. data/lib/active_model/serializer/attributes.rb +0 -82
  157. data/lib/active_model/serializer/collection_reflection.rb +0 -7
  158. data/lib/active_model/serializer/configuration.rb +0 -35
  159. data/lib/active_model/serializer/include_tree.rb +0 -111
  160. data/lib/active_model/serializer/links.rb +0 -35
  161. data/lib/active_model/serializer/meta.rb +0 -29
  162. data/lib/active_model/serializer/singular_reflection.rb +0 -7
  163. data/lib/active_model/serializer/type.rb +0 -25
  164. data/lib/active_model_serializers/key_transform.rb +0 -70
  165. data/test/active_model_serializers/key_transform_test.rb +0 -263
  166. data/test/adapter/json_api/has_many_embed_ids_test.rb +0 -43
  167. data/test/adapter/json_api/relationships_test.rb +0 -199
  168. data/test/adapter/json_api/resource_identifier_test.rb +0 -85
  169. data/test/include_tree/from_include_args_test.rb +0 -26
  170. data/test/include_tree/from_string_test.rb +0 -94
  171. data/test/include_tree/include_args_to_hash_test.rb +0 -64
@@ -1,25 +1,28 @@
1
- verbose = $VERBOSE
2
- $VERBOSE = nil
3
1
  class Model < ActiveModelSerializers::Model
4
- FILE_DIGEST = Digest::MD5.hexdigest(File.open(__FILE__).read)
2
+ rand(2).zero? && derive_attributes_from_names_and_fix_accessors
5
3
 
6
- ### Helper methods, not required to be serializable
4
+ attr_writer :id
7
5
 
8
- # Convenience when not adding @attributes readers and writers
9
- def method_missing(meth, *args)
10
- if meth.to_s =~ /^(.*)=$/
11
- attributes[$1.to_sym] = args[0]
12
- elsif attributes.key?(meth)
13
- attributes[meth]
14
- else
15
- super
6
+ # At this time, just for organization of intent
7
+ class_attribute :association_names
8
+ self.association_names = []
9
+
10
+ def self.associations(*names)
11
+ self.association_names |= names.map(&:to_sym)
12
+ # Silence redefinition of methods warnings
13
+ ActiveModelSerializers.silence_warnings do
14
+ attr_accessor(*names)
16
15
  end
17
16
  end
18
17
 
19
- # required for ActiveModel::AttributeAssignment#_assign_attribute
20
- # in Rails 5
21
- def respond_to_missing?(method_name, _include_private = false)
22
- attributes.key?(method_name.to_s.tr('=', '').to_sym) || super
18
+ def associations
19
+ association_names.each_with_object({}) do |association_name, result|
20
+ result[association_name] = public_send(association_name).freeze
21
+ end.with_indifferent_access.freeze
22
+ end
23
+
24
+ def attributes
25
+ super.except(*association_names)
23
26
  end
24
27
  end
25
28
 
@@ -30,67 +33,60 @@ end
30
33
  # model = ModelWithErrors.new
31
34
  # model.validate! # => ["cannot be nil"]
32
35
  # model.errors.full_messages # => ["name cannot be nil"]
33
- class ModelWithErrors < ::ActiveModelSerializers::Model
34
- attr_accessor :name
36
+ class ModelWithErrors < Model
37
+ attributes :name
35
38
  end
36
39
 
37
40
  class Profile < Model
41
+ attributes :name, :description
42
+ associations :comments
38
43
  end
39
-
40
44
  class ProfileSerializer < ActiveModel::Serializer
41
45
  attributes :name, :description
42
-
43
- # TODO: is this used anywhere?
44
- def arguments_passed_in?
45
- instance_options[:my_options] == :accessible
46
- end
47
46
  end
48
-
49
47
  class ProfilePreviewSerializer < ActiveModel::Serializer
50
48
  attributes :name
51
49
  end
52
50
 
53
- Post = Class.new(Model)
54
- Like = Class.new(Model)
55
- Author = Class.new(Model)
56
- Bio = Class.new(Model)
57
- Blog = Class.new(Model)
58
- Role = Class.new(Model)
59
- User = Class.new(Model)
60
- Location = Class.new(Model)
61
- Place = Class.new(Model)
62
- Tag = Class.new(Model)
63
- VirtualValue = Class.new(Model)
64
- Comment = Class.new(Model) do
65
- # Uses a custom non-time-based cache key
66
- def cache_key
67
- "#{self.class.name.downcase}/#{self.id}"
68
- end
51
+ class Author < Model
52
+ attributes :name
53
+ associations :posts, :bio, :roles, :comments
69
54
  end
55
+ class AuthorSerializer < ActiveModel::Serializer
56
+ cache key: 'writer', skip_digest: true
57
+ attribute :id
58
+ attribute :name
70
59
 
71
- class Employee < ActiveRecord::Base
72
- has_many :pictures, as: :imageable
73
- has_many :object_tags, as: :taggable
60
+ has_many :posts
61
+ has_many :roles
62
+ has_one :bio
74
63
  end
75
-
76
- class ObjectTag < ActiveRecord::Base
77
- belongs_to :poly_tag
78
- belongs_to :taggable, polymorphic: true
64
+ class AuthorPreviewSerializer < ActiveModel::Serializer
65
+ attributes :id
66
+ has_many :posts
79
67
  end
80
68
 
81
- class Picture < ActiveRecord::Base
82
- belongs_to :imageable, polymorphic: true
83
- has_many :object_tags, as: :taggable
69
+ class Comment < Model
70
+ attributes :body, :date
71
+ associations :post, :author, :likes
84
72
  end
85
-
86
- class PolyTag < ActiveRecord::Base
87
- has_many :object_tags
73
+ class CommentSerializer < ActiveModel::Serializer
74
+ cache expires_in: 1.day, skip_digest: true
75
+ attributes :id, :body
76
+ belongs_to :post
77
+ belongs_to :author
88
78
  end
79
+ class CommentPreviewSerializer < ActiveModel::Serializer
80
+ attributes :id
89
81
 
90
- module Spam; end
91
- Spam::UnrelatedLink = Class.new(Model)
82
+ belongs_to :post
83
+ end
92
84
 
93
- PostSerializer = Class.new(ActiveModel::Serializer) do
85
+ class Post < Model
86
+ attributes :title, :body
87
+ associations :author, :comments, :blog, :tags, :related
88
+ end
89
+ class PostSerializer < ActiveModel::Serializer
94
90
  cache key: 'post', expires_in: 0.1, skip_digest: true
95
91
  attributes :id, :title, :body
96
92
 
@@ -101,143 +97,116 @@ PostSerializer = Class.new(ActiveModel::Serializer) do
101
97
  def blog
102
98
  Blog.new(id: 999, name: 'Custom blog')
103
99
  end
104
-
105
- # TODO: is this used anywhere?
106
- def custom_options
107
- instance_options
108
- end
109
100
  end
110
-
111
- SpammyPostSerializer = Class.new(ActiveModel::Serializer) do
101
+ class SpammyPostSerializer < ActiveModel::Serializer
112
102
  attributes :id
113
103
  has_many :related
114
104
  end
105
+ class PostPreviewSerializer < ActiveModel::Serializer
106
+ attributes :title, :body, :id
115
107
 
116
- CommentSerializer = Class.new(ActiveModel::Serializer) do
117
- cache expires_in: 1.day, skip_digest: true
118
- attributes :id, :body
119
-
120
- belongs_to :post
121
- belongs_to :author
122
-
123
- def custom_options
124
- instance_options
125
- end
126
- end
127
-
128
- AuthorSerializer = Class.new(ActiveModel::Serializer) do
129
- cache key: 'writer', skip_digest: true
130
- attribute :id
131
- attribute :name
132
-
133
- has_many :posts
134
- has_many :roles
135
- has_one :bio
136
- end
137
-
138
- RoleSerializer = Class.new(ActiveModel::Serializer) do
139
- cache only: [:name], skip_digest: true
140
- attributes :id, :name, :description, :slug
141
-
142
- def slug
143
- "#{object.name}-#{object.id}"
144
- end
145
-
146
- belongs_to :author
147
- end
148
-
149
- LikeSerializer = Class.new(ActiveModel::Serializer) do
150
- attributes :id, :time
151
-
152
- belongs_to :likeable
108
+ has_many :comments, serializer: ::CommentPreviewSerializer
109
+ belongs_to :author, serializer: ::AuthorPreviewSerializer
153
110
  end
154
-
155
- LocationSerializer = Class.new(ActiveModel::Serializer) do
156
- cache only: [:place], skip_digest: true
157
- attributes :id, :lat, :lng
158
-
159
- belongs_to :place
160
-
161
- def place
162
- 'Nowhere'
163
- end
111
+ class PostWithCustomKeysSerializer < ActiveModel::Serializer
112
+ attributes :id
113
+ has_many :comments, key: :reviews
114
+ belongs_to :author, key: :writer
115
+ has_one :blog, key: :site
164
116
  end
165
117
 
166
- PlaceSerializer = Class.new(ActiveModel::Serializer) do
167
- attributes :id, :name
168
-
169
- has_many :locations
118
+ class Bio < Model
119
+ attributes :content, :rating
120
+ associations :author
170
121
  end
171
-
172
- BioSerializer = Class.new(ActiveModel::Serializer) do
122
+ class BioSerializer < ActiveModel::Serializer
173
123
  cache except: [:content], skip_digest: true
174
124
  attributes :id, :content, :rating
175
125
 
176
126
  belongs_to :author
177
127
  end
178
128
 
179
- BlogSerializer = Class.new(ActiveModel::Serializer) do
129
+ class Blog < Model
130
+ attributes :name, :type, :special_attribute
131
+ associations :writer, :articles
132
+ end
133
+ class BlogSerializer < ActiveModel::Serializer
180
134
  cache key: 'blog'
181
135
  attributes :id, :name
182
136
 
183
137
  belongs_to :writer
184
138
  has_many :articles
185
139
  end
186
-
187
- PaginatedSerializer = Class.new(ActiveModel::Serializer::CollectionSerializer) do
188
- def json_key
189
- 'paginated'
190
- end
191
- end
192
-
193
- AlternateBlogSerializer = Class.new(ActiveModel::Serializer) do
140
+ class AlternateBlogSerializer < ActiveModel::Serializer
194
141
  attribute :id
195
142
  attribute :name, key: :title
196
143
  end
197
-
198
- CustomBlogSerializer = Class.new(ActiveModel::Serializer) do
144
+ class CustomBlogSerializer < ActiveModel::Serializer
199
145
  attribute :id
200
146
  attribute :special_attribute
201
-
202
147
  has_many :articles
203
148
  end
204
149
 
205
- CommentPreviewSerializer = Class.new(ActiveModel::Serializer) do
206
- attributes :id
207
-
208
- belongs_to :post
150
+ class Role < Model
151
+ attributes :name, :description, :special_attribute
152
+ associations :author
209
153
  end
154
+ class RoleSerializer < ActiveModel::Serializer
155
+ cache only: [:name, :slug], skip_digest: true
156
+ attributes :id, :name, :description
157
+ attribute :friendly_id, key: :slug
158
+ belongs_to :author
210
159
 
211
- AuthorPreviewSerializer = Class.new(ActiveModel::Serializer) do
212
- attributes :id
160
+ def friendly_id
161
+ "#{object.name}-#{object.id}"
162
+ end
163
+ end
213
164
 
214
- has_many :posts
165
+ class Location < Model
166
+ attributes :lat, :lng
167
+ associations :place
215
168
  end
169
+ class LocationSerializer < ActiveModel::Serializer
170
+ cache only: [:address], skip_digest: true
171
+ attributes :id, :lat, :lng
216
172
 
217
- PostPreviewSerializer = Class.new(ActiveModel::Serializer) do
218
- attributes :title, :body, :id
173
+ belongs_to :place, key: :address
219
174
 
220
- has_many :comments, serializer: CommentPreviewSerializer
221
- belongs_to :author, serializer: AuthorPreviewSerializer
175
+ def place
176
+ 'Nowhere'
177
+ end
222
178
  end
223
179
 
224
- PostWithTagsSerializer = Class.new(ActiveModel::Serializer) do
225
- attributes :id
226
-
227
- has_many :tags
180
+ class Place < Model
181
+ attributes :name
182
+ associations :locations
183
+ end
184
+ class PlaceSerializer < ActiveModel::Serializer
185
+ attributes :id, :name
186
+ has_many :locations
228
187
  end
229
188
 
230
- PostWithCustomKeysSerializer = Class.new(ActiveModel::Serializer) do
231
- attributes :id
189
+ class Like < Model
190
+ attributes :time
191
+ associations :likeable
192
+ end
193
+ class LikeSerializer < ActiveModel::Serializer
194
+ attributes :id, :time
195
+ belongs_to :likeable
196
+ end
232
197
 
233
- has_many :comments, key: :reviews
234
- belongs_to :author, key: :writer
235
- has_one :blog, key: :site
198
+ module Spam
199
+ class UnrelatedLink < Model
200
+ end
201
+ class UnrelatedLinkSerializer < ActiveModel::Serializer
202
+ cache only: [:id]
203
+ attributes :id
204
+ end
236
205
  end
237
206
 
238
- VirtualValueSerializer = Class.new(ActiveModel::Serializer) do
207
+ class VirtualValue < Model; end
208
+ class VirtualValueSerializer < ActiveModel::Serializer
239
209
  attributes :id
240
-
241
210
  has_many :reviews, virtual_value: [{ type: 'reviews', id: '1' },
242
211
  { type: 'reviews', id: '2' }]
243
212
  has_one :maker, virtual_value: { type: 'makers', id: '1' }
@@ -249,34 +218,8 @@ VirtualValueSerializer = Class.new(ActiveModel::Serializer) do
249
218
  end
250
219
  end
251
220
 
252
- PolymorphicHasManySerializer = Class.new(ActiveModel::Serializer) do
253
- attributes :id, :name
254
- end
255
-
256
- PolymorphicBelongsToSerializer = Class.new(ActiveModel::Serializer) do
257
- attributes :id, :title
258
-
259
- has_one :imageable, serializer: PolymorphicHasManySerializer, polymorphic: true
260
- end
261
-
262
- PolymorphicSimpleSerializer = Class.new(ActiveModel::Serializer) do
263
- attributes :id
264
- end
265
-
266
- PolymorphicObjectTagSerializer = Class.new(ActiveModel::Serializer) do
267
- attributes :id
268
-
269
- has_many :taggable, serializer: PolymorphicSimpleSerializer, polymorphic: true
270
- end
271
-
272
- PolymorphicTagSerializer = Class.new(ActiveModel::Serializer) do
273
- attributes :id, :phrase
274
-
275
- has_many :object_tags, serializer: PolymorphicObjectTagSerializer
276
- end
277
-
278
- Spam::UnrelatedLinkSerializer = Class.new(ActiveModel::Serializer) do
279
- cache only: [:id]
280
- attributes :id
221
+ class PaginatedSerializer < ActiveModel::Serializer::CollectionSerializer
222
+ def json_key
223
+ 'paginated'
224
+ end
281
225
  end
282
- $VERBOSE = verbose
@@ -20,11 +20,10 @@ class SerializerGeneratorTest < Rails::Generators::TestCase
20
20
  end
21
21
 
22
22
  def test_uses_application_serializer_if_one_exists
23
- Object.const_set(:ApplicationSerializer, Class.new)
24
- run_generator
25
- assert_file 'app/serializers/account_serializer.rb', /class AccountSerializer < ApplicationSerializer/
26
- ensure
27
- Object.send :remove_const, :ApplicationSerializer
23
+ stub_safe_constantize(expected: 'ApplicationSerializer') do
24
+ run_generator
25
+ assert_file 'app/serializers/account_serializer.rb', /class AccountSerializer < ApplicationSerializer/
26
+ end
28
27
  end
29
28
 
30
29
  def test_uses_given_parent
@@ -54,4 +53,23 @@ class SerializerGeneratorTest < Rails::Generators::TestCase
54
53
  end
55
54
  end
56
55
  end
56
+
57
+ private
58
+
59
+ def stub_safe_constantize(expected:)
60
+ String.class_eval do
61
+ alias_method :old, :safe_constantize
62
+ end
63
+ String.send(:define_method, :safe_constantize) do
64
+ Class if self == expected
65
+ end
66
+
67
+ yield
68
+ ensure
69
+ String.class_eval do
70
+ undef_method :safe_constantize
71
+ alias_method :safe_constantize, :old
72
+ undef_method :old
73
+ end
74
+ end
57
75
  end
data/test/grape_test.rb CHANGED
@@ -1,82 +1,196 @@
1
1
  require 'test_helper'
2
- require 'grape'
2
+ TestHelper.silence_warnings do
3
+ require 'grape'
4
+ end
3
5
  require 'grape/active_model_serializers'
6
+ require 'kaminari'
7
+ require 'kaminari/hooks'
8
+ ::Kaminari::Hooks.init
9
+
10
+ module ActiveModelSerializers
11
+ class GrapeTest < ActiveSupport::TestCase
12
+ include Rack::Test::Methods
13
+ module Models
14
+ def self.model1
15
+ ARModels::Post.new(id: 1, title: 'Dummy Title', body: 'Lorem Ipsum')
16
+ end
4
17
 
5
- class ActiveModelSerializers::GrapeTest < ActiveSupport::TestCase
6
- include Rack::Test::Methods
7
- module Models
8
- def self.model1
9
- ARModels::Post.new(id: 1, title: 'Dummy Title', body: 'Lorem Ipsum')
10
- end
18
+ def self.model2
19
+ ARModels::Post.new(id: 2, title: 'Second Dummy Title', body: 'Second Lorem Ipsum')
20
+ end
11
21
 
12
- def self.model2
13
- ARModels::Post.new(id: 2, title: 'Second Dummy Title', body: 'Second Lorem Ipsum')
14
- end
22
+ def self.all
23
+ @all ||=
24
+ begin
25
+ model1.save!
26
+ model2.save!
27
+ ARModels::Post.all
28
+ end
29
+ end
15
30
 
16
- def self.all
17
- @all ||=
18
- begin
19
- model1.save!
20
- model2.save!
21
- ARModels::Post.all
22
- end
31
+ def self.reset_all
32
+ ARModels::Post.delete_all
33
+ @all = nil
34
+ end
35
+
36
+ def self.collection_per
37
+ 2
38
+ end
39
+
40
+ def self.collection
41
+ @collection ||=
42
+ begin
43
+ Kaminari.paginate_array(
44
+ [
45
+ Profile.new(id: 1, name: 'Name 1', description: 'Description 1', comments: 'Comments 1'),
46
+ Profile.new(id: 2, name: 'Name 2', description: 'Description 2', comments: 'Comments 2'),
47
+ Profile.new(id: 3, name: 'Name 3', description: 'Description 3', comments: 'Comments 3'),
48
+ Profile.new(id: 4, name: 'Name 4', description: 'Description 4', comments: 'Comments 4'),
49
+ Profile.new(id: 5, name: 'Name 5', description: 'Description 5', comments: 'Comments 5')
50
+ ]
51
+ ).page(1).per(collection_per)
52
+ end
53
+ end
23
54
  end
24
- end
25
55
 
26
- class GrapeTest < Grape::API
27
- format :json
28
- include Grape::ActiveModelSerializers
56
+ class GrapeTest < Grape::API
57
+ format :json
58
+ TestHelper.silence_warnings do
59
+ include Grape::ActiveModelSerializers
60
+ end
29
61
 
30
- resources :grape do
31
- get '/render' do
32
- render Models.model1
62
+ def self.resources(*)
63
+ TestHelper.silence_warnings do
64
+ super
65
+ end
33
66
  end
34
67
 
35
- get '/render_with_json_api' do
36
- post = Models.model1
37
- render post, meta: { page: 1, total_pages: 2 }, adapter: :json_api
68
+ resources :grape do
69
+ get '/render' do
70
+ render Models.model1
71
+ end
72
+
73
+ get '/render_with_json_api' do
74
+ post = Models.model1
75
+ render post, meta: { page: 1, total_pages: 2 }, adapter: :json_api
76
+ end
77
+
78
+ get '/render_array_with_json_api' do
79
+ posts = Models.all
80
+ render posts, adapter: :json_api
81
+ end
82
+
83
+ get '/render_collection_with_json_api' do
84
+ posts = Models.collection
85
+ render posts, adapter: :json_api
86
+ end
87
+
88
+ get '/render_with_implicit_formatter' do
89
+ Models.model1
90
+ end
91
+
92
+ get '/render_array_with_implicit_formatter' do
93
+ Models.all
94
+ end
95
+
96
+ get '/render_collection_with_implicit_formatter' do
97
+ Models.collection
98
+ end
38
99
  end
100
+ end
101
+
102
+ def app
103
+ Grape::Middleware::Globals.new(GrapeTest.new)
104
+ end
39
105
 
40
- get '/render_array_with_json_api' do
41
- posts = Models.all
42
- render posts, adapter: :json_api
106
+ extend Minitest::Assertions
107
+ def self.run_one_method(*)
108
+ _, stderr = capture_io do
109
+ super
43
110
  end
111
+ fail Minitest::Assertion, stderr if stderr !~ /grape/
44
112
  end
45
- end
46
113
 
47
- def app
48
- GrapeTest.new
49
- end
114
+ def test_formatter_returns_json
115
+ get '/grape/render'
116
+
117
+ post = Models.model1
118
+ serializable_resource = serializable(post)
50
119
 
51
- def test_formatter_returns_json
52
- get '/grape/render'
120
+ assert last_response.ok?
121
+ assert_equal serializable_resource.to_json, last_response.body
122
+ end
53
123
 
54
- post = Models.model1
55
- serializable_resource = serializable(post)
124
+ def test_render_helper_passes_through_options_correctly
125
+ get '/grape/render_with_json_api'
56
126
 
57
- assert last_response.ok?
58
- assert_equal serializable_resource.to_json, last_response.body
59
- end
127
+ post = Models.model1
128
+ serializable_resource = serializable(post, serializer: ARModels::PostSerializer, adapter: :json_api, meta: { page: 1, total_pages: 2 })
60
129
 
61
- def test_render_helper_passes_through_options_correctly
62
- get '/grape/render_with_json_api'
130
+ assert last_response.ok?
131
+ assert_equal serializable_resource.to_json, last_response.body
132
+ end
63
133
 
64
- post = Models.model1
65
- serializable_resource = serializable(post, serializer: ARModels::PostSerializer, adapter: :json_api, meta: { page: 1, total_pages: 2 })
134
+ def test_formatter_handles_arrays
135
+ get '/grape/render_array_with_json_api'
66
136
 
67
- assert last_response.ok?
68
- assert_equal serializable_resource.to_json, last_response.body
69
- end
137
+ posts = Models.all
138
+ serializable_resource = serializable(posts, adapter: :json_api)
70
139
 
71
- def test_formatter_handles_arrays
72
- get '/grape/render_array_with_json_api'
140
+ assert last_response.ok?
141
+ assert_equal serializable_resource.to_json, last_response.body
142
+ ensure
143
+ Models.reset_all
144
+ end
145
+
146
+ def test_formatter_handles_collections
147
+ get '/grape/render_collection_with_json_api'
148
+ assert last_response.ok?
73
149
 
74
- posts = Models.all
75
- serializable_resource = serializable(posts, adapter: :json_api)
150
+ representation = JSON.parse(last_response.body)
151
+ assert representation.include?('data')
152
+ assert representation['data'].count == Models.collection_per
153
+ assert representation.include?('links')
154
+ assert representation['links'].count > 0
155
+ end
76
156
 
77
- assert last_response.ok?
78
- assert_equal serializable_resource.to_json, last_response.body
79
- ensure
80
- ARModels::Post.delete_all
157
+ def test_implicit_formatter
158
+ post = Models.model1
159
+ serializable_resource = serializable(post, adapter: :json_api)
160
+
161
+ with_adapter :json_api do
162
+ get '/grape/render_with_implicit_formatter'
163
+ end
164
+
165
+ assert last_response.ok?
166
+ assert_equal serializable_resource.to_json, last_response.body
167
+ end
168
+
169
+ def test_implicit_formatter_handles_arrays
170
+ posts = Models.all
171
+ serializable_resource = serializable(posts, adapter: :json_api)
172
+
173
+ with_adapter :json_api do
174
+ get '/grape/render_array_with_implicit_formatter'
175
+ end
176
+
177
+ assert last_response.ok?
178
+ assert_equal serializable_resource.to_json, last_response.body
179
+ ensure
180
+ Models.reset_all
181
+ end
182
+
183
+ def test_implicit_formatter_handles_collections
184
+ with_adapter :json_api do
185
+ get '/grape/render_collection_with_implicit_formatter'
186
+ end
187
+
188
+ representation = JSON.parse(last_response.body)
189
+ assert last_response.ok?
190
+ assert representation.include?('data')
191
+ assert representation['data'].count == Models.collection_per
192
+ assert representation.include?('links')
193
+ assert representation['links'].count > 0
194
+ end
81
195
  end
82
196
  end