jsonapi-resources 0.4.2 → 0.4.3
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.
- checksums.yaml +4 -4
- data/Gemfile +2 -2
- data/README.md +103 -71
- data/Rakefile +2 -2
- data/jsonapi-resources.gemspec +2 -2
- data/lib/jsonapi-resources.rb +0 -1
- data/lib/jsonapi/active_record_operations_processor.rb +10 -2
- data/lib/jsonapi/acts_as_resource_controller.rb +26 -24
- data/lib/jsonapi/association.rb +50 -15
- data/lib/jsonapi/callbacks.rb +1 -2
- data/lib/jsonapi/configuration.rb +8 -24
- data/lib/jsonapi/error.rb +1 -2
- data/lib/jsonapi/error_codes.rb +3 -1
- data/lib/jsonapi/exceptions.rb +59 -47
- data/lib/jsonapi/include_directives.rb +11 -11
- data/lib/jsonapi/mime_types.rb +2 -2
- data/lib/jsonapi/operation.rb +28 -11
- data/lib/jsonapi/operations_processor.rb +16 -5
- data/lib/jsonapi/paginator.rb +19 -19
- data/lib/jsonapi/request.rb +175 -196
- data/lib/jsonapi/resource.rb +158 -105
- data/lib/jsonapi/resource_serializer.rb +37 -26
- data/lib/jsonapi/resources/version.rb +2 -2
- data/lib/jsonapi/response_document.rb +5 -4
- data/lib/jsonapi/routing_ext.rb +24 -19
- data/test/controllers/controller_test.rb +261 -31
- data/test/fixtures/active_record.rb +206 -8
- data/test/fixtures/book_comments.yml +2 -1
- data/test/fixtures/books.yml +1 -0
- data/test/fixtures/documents.yml +3 -0
- data/test/fixtures/people.yml +8 -1
- data/test/fixtures/pictures.yml +15 -0
- data/test/fixtures/products.yml +3 -0
- data/test/fixtures/vehicles.yml +8 -0
- data/test/helpers/{hash_helpers.rb → assertions.rb} +6 -1
- data/test/integration/requests/request_test.rb +14 -3
- data/test/integration/routes/routes_test.rb +47 -0
- data/test/test_helper.rb +27 -4
- data/test/unit/serializer/include_directives_test.rb +5 -0
- data/test/unit/serializer/polymorphic_serializer_test.rb +384 -0
- data/test/unit/serializer/serializer_test.rb +19 -1
- metadata +14 -4
@@ -22,6 +22,7 @@ module JSONAPI
|
|
22
22
|
@key_formatter = options.fetch(:key_formatter, JSONAPI.configuration.key_formatter)
|
23
23
|
@route_formatter = options.fetch(:route_formatter, JSONAPI.configuration.route_formatter)
|
24
24
|
@base_url = options.fetch(:base_url, '')
|
25
|
+
@scope_id = options[:scope_id]
|
25
26
|
end
|
26
27
|
|
27
28
|
# Converts a single resource, or an array of resources to a hash, conforming to the JSONAPI structure
|
@@ -45,7 +46,7 @@ module JSONAPI
|
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
48
|
-
primary_hash = {data: is_resource_collection ? primary_objects : primary_objects[0]}
|
49
|
+
primary_hash = { data: is_resource_collection ? primary_objects : primary_objects[0] }
|
49
50
|
|
50
51
|
primary_hash[:included] = included_objects if included_objects.size > 0
|
51
52
|
primary_hash
|
@@ -72,6 +73,7 @@ module JSONAPI
|
|
72
73
|
end
|
73
74
|
|
74
75
|
private
|
76
|
+
|
75
77
|
# Process the primary source object(s). This will then serialize associated object recursively based on the
|
76
78
|
# requested includes. Fields are controlled fields option for each resource type, such
|
77
79
|
# as fields: { people: [:id, :email, :comments], posts: [:id, :title, :author], comments: [:id, :body, :post]}
|
@@ -100,7 +102,7 @@ module JSONAPI
|
|
100
102
|
obj_hash = {}
|
101
103
|
|
102
104
|
id_format = source.class._attribute_options(:id)[:format]
|
103
|
-
#protect against ids that were declared as an attribute, but did not have a format set.
|
105
|
+
# protect against ids that were declared as an attribute, but did not have a format set.
|
104
106
|
id_format = 'id' if id_format == :default
|
105
107
|
obj_hash['id'] = format_value(source.id, id_format)
|
106
108
|
|
@@ -115,7 +117,7 @@ module JSONAPI
|
|
115
117
|
relationships = relationship_data(source, include_directives)
|
116
118
|
obj_hash['relationships'] = relationships unless relationships.nil? || relationships.empty?
|
117
119
|
|
118
|
-
|
120
|
+
obj_hash
|
119
121
|
end
|
120
122
|
|
121
123
|
def requested_fields(model)
|
@@ -125,9 +127,7 @@ module JSONAPI
|
|
125
127
|
def attribute_hash(source)
|
126
128
|
requested = requested_fields(source.class._type)
|
127
129
|
fields = source.fetchable_fields & source.class._attributes.keys.to_a
|
128
|
-
unless requested.nil?
|
129
|
-
fields = requested & fields
|
130
|
-
end
|
130
|
+
fields = requested & fields unless requested.nil?
|
131
131
|
|
132
132
|
fields.each_with_object({}) do |name, hash|
|
133
133
|
format = source.class._attribute_options(name)[:format]
|
@@ -141,9 +141,7 @@ module JSONAPI
|
|
141
141
|
associations = source.class._associations
|
142
142
|
requested = requested_fields(source.class._type)
|
143
143
|
fields = associations.keys
|
144
|
-
unless requested.nil?
|
145
|
-
fields = requested & fields
|
146
|
-
end
|
144
|
+
fields = requested & fields unless requested.nil?
|
147
145
|
|
148
146
|
field_set = Set.new(fields)
|
149
147
|
|
@@ -172,6 +170,7 @@ module JSONAPI
|
|
172
170
|
resource = source.send(name)
|
173
171
|
if resource
|
174
172
|
id = resource.id
|
173
|
+
type = association.type_for_source(source)
|
175
174
|
associations_only = already_serialized?(type, id)
|
176
175
|
if include_linkage && !associations_only
|
177
176
|
add_included_object(type, id, object_hash(resource, ia))
|
@@ -208,7 +207,12 @@ module JSONAPI
|
|
208
207
|
end
|
209
208
|
|
210
209
|
def formatted_module_path_from_klass(klass)
|
211
|
-
klass.name =~ /::[^:]+\Z/
|
210
|
+
if klass.name =~ /::[^:]+\Z/
|
211
|
+
path = (@route_formatter.format($`).freeze.gsub('::', '/') + '/').downcase
|
212
|
+
@scope_id ? "#{path}#{@scope_id}/" : path
|
213
|
+
else
|
214
|
+
''
|
215
|
+
end
|
212
216
|
end
|
213
217
|
|
214
218
|
def self_href(source)
|
@@ -217,7 +221,7 @@ module JSONAPI
|
|
217
221
|
|
218
222
|
def already_serialized?(type, id)
|
219
223
|
type = format_key(type)
|
220
|
-
|
224
|
+
@included_objects.key?(type) && @included_objects[type].key?(id)
|
221
225
|
end
|
222
226
|
|
223
227
|
def format_route(route)
|
@@ -235,8 +239,9 @@ module JSONAPI
|
|
235
239
|
def has_one_linkage(source, association)
|
236
240
|
linkage = {}
|
237
241
|
linkage_id = foreign_key_value(source, association)
|
242
|
+
|
238
243
|
if linkage_id
|
239
|
-
linkage[:type] = format_key(association.
|
244
|
+
linkage[:type] = format_key(association.type_for_source(source))
|
240
245
|
linkage[:id] = linkage_id
|
241
246
|
else
|
242
247
|
linkage = nil
|
@@ -246,9 +251,10 @@ module JSONAPI
|
|
246
251
|
|
247
252
|
def has_many_linkage(source, association)
|
248
253
|
linkage = []
|
249
|
-
|
250
|
-
|
251
|
-
|
254
|
+
linkage_types_and_values = foreign_key_types_and_values(source, association)
|
255
|
+
|
256
|
+
linkage_types_and_values.each do |type, value|
|
257
|
+
linkage.append({type: format_key(type), id: value})
|
252
258
|
end
|
253
259
|
linkage
|
254
260
|
end
|
@@ -279,15 +285,24 @@ module JSONAPI
|
|
279
285
|
end
|
280
286
|
end
|
281
287
|
|
282
|
-
# Extracts the foreign key value for
|
288
|
+
# Extracts the foreign key value for a has_one association.
|
283
289
|
def foreign_key_value(source, association)
|
284
290
|
foreign_key = association.foreign_key
|
285
291
|
value = source.send(foreign_key)
|
292
|
+
IdValueFormatter.format(value)
|
293
|
+
end
|
286
294
|
|
295
|
+
def foreign_key_types_and_values(source, association)
|
287
296
|
if association.is_a?(JSONAPI::Association::HasMany)
|
288
|
-
|
289
|
-
|
290
|
-
|
297
|
+
if association.polymorphic?
|
298
|
+
source.model.send(association.name).pluck(:type, :id).map do |type, id|
|
299
|
+
[type.pluralize, IdValueFormatter.format(id)]
|
300
|
+
end
|
301
|
+
else
|
302
|
+
source.send(association.foreign_key).map do |value|
|
303
|
+
[association.type, IdValueFormatter.format(value)]
|
304
|
+
end
|
305
|
+
end
|
291
306
|
end
|
292
307
|
end
|
293
308
|
|
@@ -301,16 +316,12 @@ module JSONAPI
|
|
301
316
|
def add_included_object(type, id, object_hash, primary = false)
|
302
317
|
type = format_key(type)
|
303
318
|
|
304
|
-
unless @included_objects.key?(type)
|
305
|
-
@included_objects[type] = {}
|
306
|
-
end
|
319
|
+
@included_objects[type] = {} unless @included_objects.key?(type)
|
307
320
|
|
308
321
|
if already_serialized?(type, id)
|
309
|
-
if primary
|
310
|
-
set_primary(type, id)
|
311
|
-
end
|
322
|
+
set_primary(type, id) if primary
|
312
323
|
else
|
313
|
-
@included_objects[type].store(id,
|
324
|
+
@included_objects[type].store(id, primary: primary, object_hash: object_hash)
|
314
325
|
end
|
315
326
|
end
|
316
327
|
|
@@ -36,7 +36,8 @@ module JSONAPI
|
|
36
36
|
fields: @options[:fields],
|
37
37
|
base_url: @options.fetch(:base_url, ''),
|
38
38
|
key_formatter: @key_formatter,
|
39
|
-
route_formatter: @options.fetch(:route_formatter, JSONAPI.configuration.route_formatter)
|
39
|
+
route_formatter: @options.fetch(:route_formatter, JSONAPI.configuration.route_formatter),
|
40
|
+
scope_id: @options[:scope_id]
|
40
41
|
)
|
41
42
|
end
|
42
43
|
|
@@ -50,7 +51,7 @@ module JSONAPI
|
|
50
51
|
@operation_results.results.each do |result|
|
51
52
|
meta.merge!(result.meta)
|
52
53
|
|
53
|
-
if JSONAPI.configuration.top_level_meta_include_record_count
|
54
|
+
if JSONAPI.configuration.top_level_meta_include_record_count && result.respond_to?(:record_count)
|
54
55
|
meta[JSONAPI.configuration.top_level_meta_record_count_key] = result.record_count
|
55
56
|
end
|
56
57
|
end
|
@@ -90,7 +91,7 @@ module JSONAPI
|
|
90
91
|
|
91
92
|
def results_to_hash
|
92
93
|
if @operation_results.has_errors?
|
93
|
-
{errors: @operation_results.all_errors}
|
94
|
+
{ errors: @operation_results.all_errors }
|
94
95
|
else
|
95
96
|
if @operation_results.results.length == 1
|
96
97
|
result = @operation_results.results[0]
|
@@ -123,4 +124,4 @@ module JSONAPI
|
|
123
124
|
end
|
124
125
|
end
|
125
126
|
end
|
126
|
-
end
|
127
|
+
end
|
data/lib/jsonapi/routing_ext.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
module ActionDispatch
|
2
2
|
module Routing
|
3
3
|
class Mapper
|
4
|
-
|
5
4
|
Resource.class_eval do
|
6
5
|
def unformat_route(route)
|
7
6
|
JSONAPI.configuration.route_formatter.unformat(route.to_s)
|
@@ -17,7 +16,7 @@ module ActionDispatch
|
|
17
16
|
JSONAPI.configuration.route_formatter.format(route.to_s)
|
18
17
|
end
|
19
18
|
|
20
|
-
def jsonapi_resource(*resources, &
|
19
|
+
def jsonapi_resource(*resources, &_block)
|
21
20
|
@resource_type = resources.first
|
22
21
|
res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type))
|
23
22
|
|
@@ -57,7 +56,7 @@ module ActionDispatch
|
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
60
|
-
def jsonapi_resources(*resources, &
|
59
|
+
def jsonapi_resources(*resources, &_block)
|
61
60
|
@resource_type = resources.first
|
62
61
|
res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type))
|
63
62
|
|
@@ -67,9 +66,10 @@ module ActionDispatch
|
|
67
66
|
|
68
67
|
options[:param] = :id
|
69
68
|
|
70
|
-
options[:path] = format_route(@resource_type)
|
69
|
+
options[:path] = format_route(options[:path] || @resource_type)
|
71
70
|
|
72
71
|
if options[:except]
|
72
|
+
options[:except] = Array(options[:except])
|
73
73
|
options[:except] << :new unless options[:except].include?(:new) || options[:except].include?('new')
|
74
74
|
options[:except] << :edit unless options[:except].include?(:edit) || options[:except].include?('edit')
|
75
75
|
else
|
@@ -92,7 +92,7 @@ module ActionDispatch
|
|
92
92
|
if only = options[:only]
|
93
93
|
Array(only).map(&:to_sym)
|
94
94
|
elsif except = options[:except]
|
95
|
-
default_methods - except
|
95
|
+
default_methods - Array(except)
|
96
96
|
else
|
97
97
|
default_methods
|
98
98
|
end
|
@@ -110,17 +110,17 @@ module ActionDispatch
|
|
110
110
|
|
111
111
|
if methods.include?(:show)
|
112
112
|
match "relationships/#{formatted_association_name}", controller: options[:controller],
|
113
|
-
|
113
|
+
action: 'show_association', association: link_type.to_s, via: [:get]
|
114
114
|
end
|
115
115
|
|
116
116
|
if methods.include?(:update)
|
117
117
|
match "relationships/#{formatted_association_name}", controller: options[:controller],
|
118
|
-
|
118
|
+
action: 'update_association', association: link_type.to_s, via: [:put, :patch]
|
119
119
|
end
|
120
120
|
|
121
121
|
if methods.include?(:destroy)
|
122
122
|
match "relationships/#{formatted_association_name}", controller: options[:controller],
|
123
|
-
|
123
|
+
action: 'destroy_association', association: link_type.to_s, via: [:delete]
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
@@ -136,22 +136,22 @@ module ActionDispatch
|
|
136
136
|
|
137
137
|
if methods.include?(:show)
|
138
138
|
match "relationships/#{formatted_association_name}", controller: options[:controller],
|
139
|
-
|
139
|
+
action: 'show_association', association: link_type.to_s, via: [:get]
|
140
140
|
end
|
141
141
|
|
142
142
|
if methods.include?(:create)
|
143
143
|
match "relationships/#{formatted_association_name}", controller: options[:controller],
|
144
|
-
|
144
|
+
action: 'create_association', association: link_type.to_s, via: [:post]
|
145
145
|
end
|
146
146
|
|
147
147
|
if methods.include?(:update)
|
148
148
|
match "relationships/#{formatted_association_name}", controller: options[:controller],
|
149
|
-
|
149
|
+
action: 'update_association', association: link_type.to_s, via: [:put, :patch]
|
150
150
|
end
|
151
151
|
|
152
152
|
if methods.include?(:destroy)
|
153
153
|
match "relationships/#{formatted_association_name}/:keys", controller: options[:controller],
|
154
|
-
|
154
|
+
action: 'destroy_association', association: link_type.to_s, via: [:delete]
|
155
155
|
end
|
156
156
|
end
|
157
157
|
|
@@ -163,13 +163,17 @@ module ActionDispatch
|
|
163
163
|
association = source._associations[association_name]
|
164
164
|
|
165
165
|
formatted_association_name = format_route(association.name)
|
166
|
-
related_resource = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(association.class_name.underscore.pluralize))
|
167
|
-
options[:controller] ||= related_resource._type.to_s
|
168
166
|
|
167
|
+
if association.polymorphic?
|
168
|
+
options[:controller] ||= association.class_name.underscore.pluralize
|
169
|
+
else
|
170
|
+
related_resource = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(association.class_name.underscore.pluralize))
|
171
|
+
options[:controller] ||= related_resource._type.to_s
|
172
|
+
end
|
169
173
|
|
170
174
|
match "#{formatted_association_name}", controller: options[:controller],
|
171
|
-
|
172
|
-
|
175
|
+
association: association.name, source: resource_type_with_module_prefix(source._type),
|
176
|
+
action: 'get_related_resource', via: [:get]
|
173
177
|
end
|
174
178
|
|
175
179
|
def jsonapi_related_resources(*association)
|
@@ -184,14 +188,15 @@ module ActionDispatch
|
|
184
188
|
options[:controller] ||= related_resource._type.to_s
|
185
189
|
|
186
190
|
match "#{formatted_association_name}", controller: options[:controller],
|
187
|
-
|
188
|
-
|
191
|
+
association: association.name, source: resource_type_with_module_prefix(source._type),
|
192
|
+
action: 'get_related_resources', via: [:get]
|
189
193
|
end
|
190
194
|
|
191
195
|
private
|
196
|
+
|
192
197
|
def resource_type_with_module_prefix(resource = nil)
|
193
198
|
resource_name = resource || @scope[:jsonapi_resource]
|
194
|
-
[@scope[:module], resource_name].compact.collect(&:to_s).join(
|
199
|
+
[@scope[:module], resource_name].compact.collect(&:to_s).join('/')
|
195
200
|
end
|
196
201
|
end
|
197
202
|
end
|
@@ -54,19 +54,19 @@ class PostsControllerTest < ActionController::TestCase
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def test_index_include_one_level_query_count
|
57
|
-
|
57
|
+
count_queries do
|
58
58
|
get :index, {include: 'author'}
|
59
59
|
end
|
60
60
|
assert_response :success
|
61
|
-
|
61
|
+
assert_query_count(2)
|
62
62
|
end
|
63
63
|
|
64
64
|
def test_index_include_two_levels_query_count
|
65
|
-
|
65
|
+
count_queries do
|
66
66
|
get :index, {include: 'author,author.comments'}
|
67
67
|
end
|
68
68
|
assert_response :success
|
69
|
-
|
69
|
+
assert_query_count(3)
|
70
70
|
end
|
71
71
|
|
72
72
|
def test_index_filter_by_ids_and_fields
|
@@ -76,10 +76,10 @@ class PostsControllerTest < ActionController::TestCase
|
|
76
76
|
|
77
77
|
# type, id, links, attributes, relationships
|
78
78
|
assert_equal 5, json_response['data'][0].size
|
79
|
-
assert json_response['data'][0].
|
80
|
-
assert json_response['data'][0].
|
81
|
-
assert json_response['data'][0]['attributes'].
|
82
|
-
assert json_response['data'][0].
|
79
|
+
assert json_response['data'][0].key?('type')
|
80
|
+
assert json_response['data'][0].key?('id')
|
81
|
+
assert json_response['data'][0]['attributes'].key?('title')
|
82
|
+
assert json_response['data'][0].key?('links')
|
83
83
|
end
|
84
84
|
|
85
85
|
def test_index_filter_by_ids_and_fields_specify_type
|
@@ -89,10 +89,10 @@ class PostsControllerTest < ActionController::TestCase
|
|
89
89
|
|
90
90
|
# type, id, links, attributes, relationships
|
91
91
|
assert_equal 5, json_response['data'][0].size
|
92
|
-
assert json_response['data'][0].
|
93
|
-
assert json_response['data'][0].
|
94
|
-
assert json_response['data'][0]['attributes'].
|
95
|
-
assert json_response['data'][0].
|
92
|
+
assert json_response['data'][0].key?('type')
|
93
|
+
assert json_response['data'][0].key?('id')
|
94
|
+
assert json_response['data'][0]['attributes'].key?('title')
|
95
|
+
assert json_response['data'][0].key?('links')
|
96
96
|
end
|
97
97
|
|
98
98
|
def test_index_filter_by_ids_and_fields_specify_unrelated_type
|
@@ -108,13 +108,16 @@ class PostsControllerTest < ActionController::TestCase
|
|
108
108
|
|
109
109
|
# type, id, links, relationships
|
110
110
|
assert_equal 4, json_response['data'][0].size
|
111
|
-
assert json_response['data'][0].
|
112
|
-
assert json_response['data'][0].
|
113
|
-
assert json_response['data'][0]['relationships'].
|
111
|
+
assert json_response['data'][0].key?('type')
|
112
|
+
assert json_response['data'][0].key?('id')
|
113
|
+
assert json_response['data'][0]['relationships'].key?('author')
|
114
114
|
end
|
115
115
|
|
116
116
|
def test_filter_association_single
|
117
|
-
|
117
|
+
count_queries do
|
118
|
+
get :index, {filter: {tags: '5,1'}}
|
119
|
+
end
|
120
|
+
assert_query_count(1)
|
118
121
|
assert_response :success
|
119
122
|
assert_equal 3, json_response['data'].size
|
120
123
|
assert_match /New post/, response.body
|
@@ -123,7 +126,10 @@ class PostsControllerTest < ActionController::TestCase
|
|
123
126
|
end
|
124
127
|
|
125
128
|
def test_filter_associations_multiple
|
126
|
-
|
129
|
+
count_queries do
|
130
|
+
get :index, {filter: {tags: '5,1', comments: '3'}}
|
131
|
+
end
|
132
|
+
assert_query_count(1)
|
127
133
|
assert_response :success
|
128
134
|
assert_equal 1, json_response['data'].size
|
129
135
|
assert_match /JR Solves your serialization woes!/, response.body
|
@@ -227,6 +233,15 @@ class PostsControllerTest < ActionController::TestCase
|
|
227
233
|
assert_nil json_response['included']
|
228
234
|
end
|
229
235
|
|
236
|
+
def test_show_does_not_include_records_count_in_meta
|
237
|
+
JSONAPI.configuration.top_level_meta_include_record_count = true
|
238
|
+
get :show, { id: Post.first.id }
|
239
|
+
assert_response :success
|
240
|
+
assert_equal json_response['meta'], nil
|
241
|
+
ensure
|
242
|
+
JSONAPI.configuration.top_level_meta_include_record_count = false
|
243
|
+
end
|
244
|
+
|
230
245
|
def test_show_single_with_includes
|
231
246
|
get :show, {id: '1', include: 'comments'}
|
232
247
|
assert_response :success
|
@@ -317,7 +332,7 @@ class PostsControllerTest < ActionController::TestCase
|
|
317
332
|
}
|
318
333
|
|
319
334
|
assert_response :unprocessable_entity
|
320
|
-
#
|
335
|
+
# TODO: check if this validation is working
|
321
336
|
assert_match /author - can't be blank/, response.body
|
322
337
|
end
|
323
338
|
|
@@ -621,6 +636,28 @@ class PostsControllerTest < ActionController::TestCase
|
|
621
636
|
json_response['data']['relationships']['tags']['data'])
|
622
637
|
end
|
623
638
|
|
639
|
+
def test_update_with_internal_server_error
|
640
|
+
set_content_type_header!
|
641
|
+
post_object = Post.find(3)
|
642
|
+
title = post_object.title
|
643
|
+
|
644
|
+
put :update,
|
645
|
+
{
|
646
|
+
id: 3,
|
647
|
+
data: {
|
648
|
+
id: '3',
|
649
|
+
type: 'posts',
|
650
|
+
attributes: {
|
651
|
+
title: 'BOOM'
|
652
|
+
}
|
653
|
+
}
|
654
|
+
}
|
655
|
+
|
656
|
+
assert_response 500
|
657
|
+
post_object = Post.find(3)
|
658
|
+
assert_equal title, post_object.title
|
659
|
+
end
|
660
|
+
|
624
661
|
def test_update_remove_links
|
625
662
|
set_content_type_header!
|
626
663
|
put :update,
|
@@ -1518,7 +1555,7 @@ class ExpenseEntriesControllerTest < ActionController::TestCase
|
|
1518
1555
|
get :show, {id: 1, include: 'isoCurrency,employee', 'fields' => {'expenseEntries' => 'transactionDate'}}
|
1519
1556
|
assert_response :success
|
1520
1557
|
assert json_response['data'].is_a?(Hash)
|
1521
|
-
assert json_response['data']['attributes'].
|
1558
|
+
assert json_response['data']['attributes'].key?('transactionDate')
|
1522
1559
|
assert_equal 2, json_response['included'].size
|
1523
1560
|
end
|
1524
1561
|
|
@@ -1527,7 +1564,7 @@ class ExpenseEntriesControllerTest < ActionController::TestCase
|
|
1527
1564
|
'isoCurrencies' => 'id,name'}}
|
1528
1565
|
assert_response :success
|
1529
1566
|
assert json_response['data'].is_a?(Hash)
|
1530
|
-
assert json_response['data']['attributes'].
|
1567
|
+
assert json_response['data']['attributes'].key?('transactionDate')
|
1531
1568
|
assert_equal 2, json_response['included'].size
|
1532
1569
|
end
|
1533
1570
|
|
@@ -1863,7 +1900,7 @@ class PeopleControllerTest < ActionController::TestCase
|
|
1863
1900
|
def test_get_related_resource
|
1864
1901
|
JSONAPI.configuration.json_key_format = :dasherized_key
|
1865
1902
|
JSONAPI.configuration.route_format = :underscored_key
|
1866
|
-
get :get_related_resource, {post_id: '2', association: 'author', :
|
1903
|
+
get :get_related_resource, {post_id: '2', association: 'author', source:'posts'}
|
1867
1904
|
assert_response :success
|
1868
1905
|
assert_hash_equals(
|
1869
1906
|
{
|
@@ -1907,7 +1944,13 @@ class PeopleControllerTest < ActionController::TestCase
|
|
1907
1944
|
"related" => "http://test.host/people/1/hair_cut"
|
1908
1945
|
},
|
1909
1946
|
"data" => nil
|
1910
|
-
|
1947
|
+
},
|
1948
|
+
vehicles: {
|
1949
|
+
links: {
|
1950
|
+
self: "http://test.host/people/1/relationships/vehicles",
|
1951
|
+
related: "http://test.host/people/1/vehicles"
|
1952
|
+
}
|
1953
|
+
}
|
1911
1954
|
}
|
1912
1955
|
}
|
1913
1956
|
},
|
@@ -1916,7 +1959,7 @@ class PeopleControllerTest < ActionController::TestCase
|
|
1916
1959
|
end
|
1917
1960
|
|
1918
1961
|
def test_get_related_resource_nil
|
1919
|
-
get :get_related_resource, {post_id: '17', association: 'author', :
|
1962
|
+
get :get_related_resource, {post_id: '17', association: 'author', source:'posts'}
|
1920
1963
|
assert_response :success
|
1921
1964
|
assert_hash_equals json_response,
|
1922
1965
|
{
|
@@ -2133,6 +2176,7 @@ end
|
|
2133
2176
|
class Api::V2::BooksControllerTest < ActionController::TestCase
|
2134
2177
|
def setup
|
2135
2178
|
JSONAPI.configuration.json_key_format = :dasherized_key
|
2179
|
+
$test_user = Person.find(1)
|
2136
2180
|
end
|
2137
2181
|
|
2138
2182
|
def after_teardown
|
@@ -2155,7 +2199,7 @@ class Api::V2::BooksControllerTest < ActionController::TestCase
|
|
2155
2199
|
JSONAPI.configuration.top_level_meta_include_record_count = false
|
2156
2200
|
|
2157
2201
|
assert_response :success
|
2158
|
-
assert_equal
|
2202
|
+
assert_equal 901, json_response['meta']['record-count']
|
2159
2203
|
assert_equal 10, json_response['data'].size
|
2160
2204
|
assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
|
2161
2205
|
end
|
@@ -2170,7 +2214,7 @@ class Api::V2::BooksControllerTest < ActionController::TestCase
|
|
2170
2214
|
JSONAPI.configuration.top_level_meta_record_count_key = :record_count
|
2171
2215
|
|
2172
2216
|
assert_response :success
|
2173
|
-
assert_equal
|
2217
|
+
assert_equal 901, json_response['meta']['total-records']
|
2174
2218
|
assert_equal 10, json_response['data'].size
|
2175
2219
|
assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
|
2176
2220
|
end
|
@@ -2178,25 +2222,25 @@ class Api::V2::BooksControllerTest < ActionController::TestCase
|
|
2178
2222
|
def test_books_offset_pagination_no_params_includes_query_count_one_level
|
2179
2223
|
Api::V2::BookResource.paginator :offset
|
2180
2224
|
|
2181
|
-
|
2225
|
+
count_queries do
|
2182
2226
|
get :index, {include: 'book-comments'}
|
2183
2227
|
end
|
2184
2228
|
assert_response :success
|
2185
2229
|
assert_equal 10, json_response['data'].size
|
2186
2230
|
assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
|
2187
|
-
|
2231
|
+
assert_query_count(3)
|
2188
2232
|
end
|
2189
2233
|
|
2190
2234
|
def test_books_offset_pagination_no_params_includes_query_count_two_levels
|
2191
2235
|
Api::V2::BookResource.paginator :offset
|
2192
2236
|
|
2193
|
-
|
2237
|
+
count_queries do
|
2194
2238
|
get :index, {include: 'book-comments,book-comments.author'}
|
2195
2239
|
end
|
2196
2240
|
assert_response :success
|
2197
2241
|
assert_equal 10, json_response['data'].size
|
2198
2242
|
assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
|
2199
|
-
|
2243
|
+
assert_query_count(4)
|
2200
2244
|
end
|
2201
2245
|
|
2202
2246
|
def test_books_offset_pagination
|
@@ -2315,6 +2359,192 @@ class Api::V2::BooksControllerTest < ActionController::TestCase
|
|
2315
2359
|
assert_equal 10, json_response['data'].size
|
2316
2360
|
assert_equal 'Book 20', json_response['data'][0]['attributes']['title']
|
2317
2361
|
end
|
2362
|
+
|
2363
|
+
def test_books_included_paged
|
2364
|
+
Api::V2::BookResource.paginator :offset
|
2365
|
+
|
2366
|
+
count_queries do
|
2367
|
+
get :index, {filter: {id: '0'}, include: 'book-comments'}
|
2368
|
+
end
|
2369
|
+
assert_response :success
|
2370
|
+
assert_equal 1, json_response['data'].size
|
2371
|
+
assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
|
2372
|
+
assert_query_count(3)
|
2373
|
+
end
|
2374
|
+
|
2375
|
+
def test_books_banned_non_book_admin
|
2376
|
+
$test_user = Person.find(1)
|
2377
|
+
Api::V2::BookResource.paginator :offset
|
2378
|
+
count_queries do
|
2379
|
+
JSONAPI.configuration.top_level_meta_include_record_count = true
|
2380
|
+
get :index, {page: {offset: 50, limit: 12}}
|
2381
|
+
JSONAPI.configuration.top_level_meta_include_record_count = false
|
2382
|
+
end
|
2383
|
+
assert_response :success
|
2384
|
+
assert_equal 12, json_response['data'].size
|
2385
|
+
assert_equal 'Book 50', json_response['data'][0]['attributes']['title']
|
2386
|
+
assert_equal 901, json_response['meta']['record-count']
|
2387
|
+
assert_query_count(2)
|
2388
|
+
end
|
2389
|
+
|
2390
|
+
def test_books_banned_non_book_admin_includes_switched
|
2391
|
+
$test_user = Person.find(1)
|
2392
|
+
Api::V2::BookResource.paginator :offset
|
2393
|
+
count_queries do
|
2394
|
+
JSONAPI.configuration.top_level_meta_include_record_count = true
|
2395
|
+
get :index, {page: {offset: 0, limit: 12}, include: 'book-comments'}
|
2396
|
+
JSONAPI.configuration.top_level_meta_include_record_count = false
|
2397
|
+
end
|
2398
|
+
|
2399
|
+
assert_response :success
|
2400
|
+
assert_equal 12, json_response['data'].size
|
2401
|
+
assert_equal 130, json_response['included'].size
|
2402
|
+
assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
|
2403
|
+
assert_equal 26, json_response['data'][0]['relationships']['book-comments']['data'].size
|
2404
|
+
assert_equal 'book-comments', json_response['included'][0]['type']
|
2405
|
+
assert_equal 901, json_response['meta']['record-count']
|
2406
|
+
assert_query_count(3)
|
2407
|
+
end
|
2408
|
+
|
2409
|
+
def test_books_banned_non_book_admin_includes_nested_includes
|
2410
|
+
$test_user = Person.find(1)
|
2411
|
+
Api::V2::BookResource.paginator :offset
|
2412
|
+
count_queries do
|
2413
|
+
JSONAPI.configuration.top_level_meta_include_record_count = true
|
2414
|
+
get :index, {page: {offset: 0, limit: 12}, include: 'book-comments.author'}
|
2415
|
+
JSONAPI.configuration.top_level_meta_include_record_count = false
|
2416
|
+
end
|
2417
|
+
assert_response :success
|
2418
|
+
assert_equal 12, json_response['data'].size
|
2419
|
+
assert_equal 131, json_response['included'].size
|
2420
|
+
assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
|
2421
|
+
assert_equal 901, json_response['meta']['record-count']
|
2422
|
+
assert_query_count(4)
|
2423
|
+
end
|
2424
|
+
|
2425
|
+
def test_books_banned_admin
|
2426
|
+
$test_user = Person.find(5)
|
2427
|
+
Api::V2::BookResource.paginator :offset
|
2428
|
+
query_count = count_queries do
|
2429
|
+
JSONAPI.configuration.top_level_meta_include_record_count = true
|
2430
|
+
get :index, {page: {offset: 50, limit: 12}, filter: {banned: 'true'}}
|
2431
|
+
JSONAPI.configuration.top_level_meta_include_record_count = false
|
2432
|
+
end
|
2433
|
+
assert_response :success
|
2434
|
+
assert_equal 12, json_response['data'].size
|
2435
|
+
assert_equal 'Book 651', json_response['data'][0]['attributes']['title']
|
2436
|
+
assert_equal 99, json_response['meta']['record-count']
|
2437
|
+
assert_query_count(2)
|
2438
|
+
end
|
2439
|
+
|
2440
|
+
def test_books_not_banned_admin
|
2441
|
+
$test_user = Person.find(5)
|
2442
|
+
Api::V2::BookResource.paginator :offset
|
2443
|
+
count_queries do
|
2444
|
+
JSONAPI.configuration.top_level_meta_include_record_count = true
|
2445
|
+
get :index, {page: {offset: 50, limit: 12}, filter: {banned: 'false'}}
|
2446
|
+
JSONAPI.configuration.top_level_meta_include_record_count = false
|
2447
|
+
end
|
2448
|
+
assert_response :success
|
2449
|
+
assert_equal 12, json_response['data'].size
|
2450
|
+
assert_equal 'Book 50', json_response['data'][0]['attributes']['title']
|
2451
|
+
assert_equal 901, json_response['meta']['record-count']
|
2452
|
+
assert_query_count(2)
|
2453
|
+
end
|
2454
|
+
|
2455
|
+
def test_books_banned_non_book_admin_overlapped
|
2456
|
+
$test_user = Person.find(1)
|
2457
|
+
Api::V2::BookResource.paginator :offset
|
2458
|
+
count_queries do
|
2459
|
+
JSONAPI.configuration.top_level_meta_include_record_count = true
|
2460
|
+
get :index, {page: {offset: 590, limit: 20}}
|
2461
|
+
JSONAPI.configuration.top_level_meta_include_record_count = false
|
2462
|
+
end
|
2463
|
+
assert_response :success
|
2464
|
+
assert_equal 20, json_response['data'].size
|
2465
|
+
assert_equal 'Book 590', json_response['data'][0]['attributes']['title']
|
2466
|
+
assert_equal 901, json_response['meta']['record-count']
|
2467
|
+
assert_query_count(2)
|
2468
|
+
end
|
2469
|
+
|
2470
|
+
def test_books_included_exclude_unapproved
|
2471
|
+
$test_user = Person.find(1)
|
2472
|
+
Api::V2::BookResource.paginator :none
|
2473
|
+
|
2474
|
+
count_queries do
|
2475
|
+
get :index, {filter: {id: '0,1,2,3,4'}, include: 'book-comments'}
|
2476
|
+
end
|
2477
|
+
assert_response :success
|
2478
|
+
assert_equal 5, json_response['data'].size
|
2479
|
+
assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
|
2480
|
+
assert_equal 130, json_response['included'].size
|
2481
|
+
assert_equal 26, json_response['data'][0]['relationships']['book-comments']['data'].size
|
2482
|
+
assert_query_count(2)
|
2483
|
+
end
|
2484
|
+
|
2485
|
+
def test_books_included_all_comments_for_admin
|
2486
|
+
$test_user = Person.find(5)
|
2487
|
+
Api::V2::BookResource.paginator :none
|
2488
|
+
|
2489
|
+
get :index, {filter: {id: '0,1,2,3,4'}, include: 'book-comments'}
|
2490
|
+
assert_response :success
|
2491
|
+
assert_equal 5, json_response['data'].size
|
2492
|
+
assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
|
2493
|
+
assert_equal 255, json_response['included'].size
|
2494
|
+
assert_equal 51, json_response['data'][0]['relationships']['book-comments']['data'].size
|
2495
|
+
end
|
2496
|
+
|
2497
|
+
def test_books_filter_by_book_comment_id_limited_user
|
2498
|
+
$test_user = Person.find(1)
|
2499
|
+
get :index, {filter: {book_comments: '0,52' }}
|
2500
|
+
assert_response :success
|
2501
|
+
assert_equal 1, json_response['data'].size
|
2502
|
+
end
|
2503
|
+
|
2504
|
+
def test_books_filter_by_book_comment_id_admin_user
|
2505
|
+
$test_user = Person.find(5)
|
2506
|
+
get :index, {filter: {book_comments: '0,52' }}
|
2507
|
+
assert_response :success
|
2508
|
+
assert_equal 2, json_response['data'].size
|
2509
|
+
end
|
2510
|
+
end
|
2511
|
+
|
2512
|
+
class Api::V2::BookCommentsControllerTest < ActionController::TestCase
|
2513
|
+
def setup
|
2514
|
+
JSONAPI.configuration.json_key_format = :dasherized_key
|
2515
|
+
Api::V2::BookCommentResource.paginator :none
|
2516
|
+
$test_user = Person.find(1)
|
2517
|
+
end
|
2518
|
+
|
2519
|
+
def test_book_comments_all_for_admin
|
2520
|
+
$test_user = Person.find(5)
|
2521
|
+
count_queries do
|
2522
|
+
get :index
|
2523
|
+
end
|
2524
|
+
assert_response :success
|
2525
|
+
assert_equal 255, json_response['data'].size
|
2526
|
+
assert_query_count(1)
|
2527
|
+
end
|
2528
|
+
|
2529
|
+
def test_book_comments_unapproved_context_based
|
2530
|
+
$test_user = Person.find(5)
|
2531
|
+
count_queries do
|
2532
|
+
get :index, {filter: {approved: 'false'}}
|
2533
|
+
end
|
2534
|
+
assert_response :success
|
2535
|
+
assert_equal 125, json_response['data'].size
|
2536
|
+
assert_query_count(1)
|
2537
|
+
end
|
2538
|
+
|
2539
|
+
def test_book_comments_exclude_unapproved_context_based
|
2540
|
+
$test_user = Person.find(1)
|
2541
|
+
count_queries do
|
2542
|
+
get :index
|
2543
|
+
end
|
2544
|
+
assert_response :success
|
2545
|
+
assert_equal 130, json_response['data'].size
|
2546
|
+
assert_query_count(1)
|
2547
|
+
end
|
2318
2548
|
end
|
2319
2549
|
|
2320
2550
|
class Api::V4::BooksControllerTest < ActionController::TestCase
|
@@ -2329,7 +2559,7 @@ class Api::V4::BooksControllerTest < ActionController::TestCase
|
|
2329
2559
|
assert_response :success
|
2330
2560
|
assert_equal 12, json_response['data'].size
|
2331
2561
|
assert_equal 'Book 50', json_response['data'][0]['attributes']['title']
|
2332
|
-
assert_equal
|
2562
|
+
assert_equal 901, json_response['meta']['totalRecords']
|
2333
2563
|
JSONAPI.configuration.operations_processor = :active_record
|
2334
2564
|
end
|
2335
2565
|
|
@@ -2397,4 +2627,4 @@ class Api::V1::PlanetsControllerTest < ActionController::TestCase
|
|
2397
2627
|
assert_response :unprocessable_entity
|
2398
2628
|
assert_match /Save failed or was cancelled/, json_response['errors'][0]['detail']
|
2399
2629
|
end
|
2400
|
-
end
|
2630
|
+
end
|