jsonapi-resources 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|