sanger-jsonapi-resources 0.1.1 → 0.2.0
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/LICENSE.txt +1 -1
- data/README.md +35 -12
- data/lib/bug_report_templates/rails_5_latest.rb +125 -0
- data/lib/bug_report_templates/rails_5_master.rb +140 -0
- data/lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb +26 -0
- data/lib/jsonapi/active_relation/join_manager.rb +297 -0
- data/lib/jsonapi/active_relation_resource.rb +898 -0
- data/lib/jsonapi/acts_as_resource_controller.rb +130 -113
- data/lib/jsonapi/basic_resource.rb +1164 -0
- data/lib/jsonapi/cached_response_fragment.rb +129 -0
- data/lib/jsonapi/callbacks.rb +2 -0
- data/lib/jsonapi/compatibility_helper.rb +29 -0
- data/lib/jsonapi/compiled_json.rb +13 -1
- data/lib/jsonapi/configuration.rb +88 -21
- data/lib/jsonapi/error.rb +29 -0
- data/lib/jsonapi/error_codes.rb +4 -0
- data/lib/jsonapi/exceptions.rb +82 -50
- data/lib/jsonapi/formatter.rb +5 -3
- data/lib/jsonapi/include_directives.rb +22 -67
- data/lib/jsonapi/link_builder.rb +76 -80
- data/lib/jsonapi/mime_types.rb +6 -10
- data/lib/jsonapi/naive_cache.rb +2 -0
- data/lib/jsonapi/operation.rb +18 -5
- data/lib/jsonapi/operation_result.rb +76 -16
- data/lib/jsonapi/paginator.rb +2 -0
- data/lib/jsonapi/path.rb +45 -0
- data/lib/jsonapi/path_segment.rb +78 -0
- data/lib/jsonapi/processor.rb +193 -115
- data/lib/jsonapi/relationship.rb +145 -14
- data/lib/jsonapi/request.rb +734 -0
- data/lib/jsonapi/resource.rb +3 -1251
- data/lib/jsonapi/resource_controller.rb +2 -0
- data/lib/jsonapi/resource_controller_metal.rb +7 -1
- data/lib/jsonapi/resource_fragment.rb +56 -0
- data/lib/jsonapi/resource_identity.rb +44 -0
- data/lib/jsonapi/resource_serializer.rb +158 -284
- data/lib/jsonapi/resource_set.rb +196 -0
- data/lib/jsonapi/resource_tree.rb +236 -0
- data/lib/jsonapi/resources/railtie.rb +9 -0
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/response_document.rb +107 -83
- data/lib/jsonapi/routing_ext.rb +50 -26
- data/lib/jsonapi-resources.rb +23 -5
- data/lib/tasks/check_upgrade.rake +52 -0
- metadata +43 -31
- data/lib/jsonapi/cached_resource_fragment.rb +0 -127
- data/lib/jsonapi/operation_dispatcher.rb +0 -88
- data/lib/jsonapi/operation_results.rb +0 -35
- data/lib/jsonapi/relationship_builder.rb +0 -167
- data/lib/jsonapi/request_parser.rb +0 -678
data/lib/jsonapi/exceptions.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JSONAPI
|
2
4
|
module Exceptions
|
3
5
|
class Error < RuntimeError
|
4
|
-
|
6
|
+
attr_reader :error_object_overrides
|
5
7
|
|
6
8
|
def initialize(error_object_overrides = {})
|
7
9
|
@error_object_overrides = error_object_overrides
|
@@ -18,6 +20,22 @@ module JSONAPI
|
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
23
|
+
class Errors < Error
|
24
|
+
def initialize(errors, error_object_overrides = {})
|
25
|
+
@errors = errors
|
26
|
+
|
27
|
+
@errors.each do |error|
|
28
|
+
error.update_with_overrides(error_object_overrides)
|
29
|
+
end
|
30
|
+
|
31
|
+
super(error_object_overrides)
|
32
|
+
end
|
33
|
+
|
34
|
+
def errors
|
35
|
+
@errors
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
21
39
|
class InternalServerError < Error
|
22
40
|
attr_accessor :exception
|
23
41
|
|
@@ -33,6 +51,12 @@ module JSONAPI
|
|
33
51
|
meta[:backtrace] = exception.backtrace
|
34
52
|
end
|
35
53
|
|
54
|
+
if JSONAPI.configuration.include_application_backtraces_in_errors
|
55
|
+
meta ||= Hash.new
|
56
|
+
meta[:exception] ||= exception.message
|
57
|
+
meta[:application_backtrace] = exception.backtrace.select{|line| line =~ /#{Rails.root}/}
|
58
|
+
end
|
59
|
+
|
36
60
|
[create_error_object(code: JSONAPI::INTERNAL_SERVER_ERROR,
|
37
61
|
status: :internal_server_error,
|
38
62
|
title: I18n.t('jsonapi-resources.exceptions.internal_server_error.title',
|
@@ -119,49 +143,30 @@ module JSONAPI
|
|
119
143
|
end
|
120
144
|
end
|
121
145
|
|
122
|
-
|
123
|
-
class HasManyRelationExists < Error
|
124
|
-
attr_accessor :id
|
125
|
-
|
126
|
-
def initialize(id, error_object_overrides = {})
|
127
|
-
@id = id
|
128
|
-
super(error_object_overrides)
|
129
|
-
end
|
130
|
-
|
131
|
-
def errors
|
132
|
-
[create_error_object(code: JSONAPI::RELATION_EXISTS,
|
133
|
-
status: :bad_request,
|
134
|
-
title: I18n.translate('jsonapi-resources.exceptions.has_many_relation.title',
|
135
|
-
default: 'Relation exists'),
|
136
|
-
detail: I18n.translate('jsonapi-resources.exceptions.has_many_relation.detail',
|
137
|
-
default: "The relation to #{id} already exists.",
|
138
|
-
id: id))]
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
146
|
class BadRequest < Error
|
143
|
-
def initialize(exception)
|
147
|
+
def initialize(exception, error_object_overrides = {})
|
144
148
|
@exception = exception
|
149
|
+
super(error_object_overrides)
|
145
150
|
end
|
146
151
|
|
147
152
|
def errors
|
148
|
-
[
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
153
|
+
[create_error_object(code: JSONAPI::BAD_REQUEST,
|
154
|
+
status: :bad_request,
|
155
|
+
title: I18n.translate('jsonapi-resources.exceptions.bad_request.title',
|
156
|
+
default: 'Bad Request'),
|
157
|
+
detail: I18n.translate('jsonapi-resources.exceptions.bad_request.detail',
|
158
|
+
default: @exception))]
|
154
159
|
end
|
155
160
|
end
|
156
161
|
|
157
162
|
class InvalidRequestFormat < Error
|
158
163
|
def errors
|
159
|
-
[
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
164
|
+
[create_error_object(code: JSONAPI::BAD_REQUEST,
|
165
|
+
status: :bad_request,
|
166
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_request_format.title',
|
167
|
+
default: 'Bad Request'),
|
168
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_request_format.detail',
|
169
|
+
default: 'Request must be a hash'))]
|
165
170
|
end
|
166
171
|
end
|
167
172
|
|
@@ -324,6 +329,26 @@ module JSONAPI
|
|
324
329
|
end
|
325
330
|
end
|
326
331
|
|
332
|
+
class InvalidRelationship < Error
|
333
|
+
attr_accessor :relationship_name, :type
|
334
|
+
|
335
|
+
def initialize(type, relationship_name, error_object_overrides = {})
|
336
|
+
@relationship_name = relationship_name
|
337
|
+
@type = type
|
338
|
+
super(error_object_overrides)
|
339
|
+
end
|
340
|
+
|
341
|
+
def errors
|
342
|
+
[create_error_object(code: JSONAPI::INVALID_RELATIONSHIP,
|
343
|
+
status: :bad_request,
|
344
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_relationship.title',
|
345
|
+
default: 'Invalid relationship'),
|
346
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_relationship.detail',
|
347
|
+
default: "#{relationship_name} is not a valid field for #{type}.",
|
348
|
+
relationship_name: relationship_name, type: type))]
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
327
352
|
class InvalidInclude < Error
|
328
353
|
attr_accessor :relationship, :resource
|
329
354
|
|
@@ -339,7 +364,7 @@ module JSONAPI
|
|
339
364
|
title: I18n.translate('jsonapi-resources.exceptions.invalid_include.title',
|
340
365
|
default: 'Invalid field'),
|
341
366
|
detail: I18n.translate('jsonapi-resources.exceptions.invalid_include.detail',
|
342
|
-
default: "#{relationship} is not a valid relationship of #{resource}",
|
367
|
+
default: "#{relationship} is not a valid includable relationship of #{resource}",
|
343
368
|
relationship: relationship, resource: resource))]
|
344
369
|
end
|
345
370
|
end
|
@@ -364,24 +389,21 @@ module JSONAPI
|
|
364
389
|
end
|
365
390
|
end
|
366
391
|
|
367
|
-
class
|
368
|
-
attr_accessor :
|
392
|
+
class ParameterNotAllowed < Error
|
393
|
+
attr_accessor :param
|
369
394
|
|
370
|
-
def initialize(
|
371
|
-
@
|
395
|
+
def initialize(param, error_object_overrides = {})
|
396
|
+
@param = param
|
372
397
|
super(error_object_overrides)
|
373
398
|
end
|
374
399
|
|
375
400
|
def errors
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
default: "#{param} is not allowed.", param: param))
|
383
|
-
|
384
|
-
end
|
401
|
+
[create_error_object(code: JSONAPI::PARAM_NOT_ALLOWED,
|
402
|
+
status: :bad_request,
|
403
|
+
title: I18n.translate('jsonapi-resources.exceptions.parameter_not_allowed.title',
|
404
|
+
default: 'Param not allowed'),
|
405
|
+
detail: I18n.translate('jsonapi-resources.exceptions.parameters_not_allowed.detail',
|
406
|
+
default: "#{param} is not allowed.", param: param))]
|
385
407
|
end
|
386
408
|
end
|
387
409
|
|
@@ -451,11 +473,12 @@ module JSONAPI
|
|
451
473
|
end
|
452
474
|
|
453
475
|
class ValidationErrors < Error
|
454
|
-
attr_reader :error_messages, :error_metadata, :resource_relationships
|
476
|
+
attr_reader :error_messages, :error_metadata, :resource_relationships, :resource_class
|
455
477
|
|
456
478
|
def initialize(resource, error_object_overrides = {})
|
457
479
|
@error_messages = resource.model_error_messages
|
458
480
|
@error_metadata = resource.validation_error_metadata
|
481
|
+
@resource_class = resource.class
|
459
482
|
@resource_relationships = resource.class._relationships.keys
|
460
483
|
@key_formatter = JSONAPI.configuration.key_formatter
|
461
484
|
super(error_object_overrides)
|
@@ -477,7 +500,7 @@ module JSONAPI
|
|
477
500
|
create_error_object(code: JSONAPI::VALIDATION_ERROR,
|
478
501
|
status: :unprocessable_entity,
|
479
502
|
title: message,
|
480
|
-
detail:
|
503
|
+
detail: detail(attr_key, message),
|
481
504
|
source: { pointer: pointer(attr_key) },
|
482
505
|
meta: metadata_for(attr_key, message))
|
483
506
|
end
|
@@ -487,7 +510,12 @@ module JSONAPI
|
|
487
510
|
error_metadata[attr_key] ? error_metadata[attr_key][message] : nil
|
488
511
|
end
|
489
512
|
|
513
|
+
def detail(attr_key, message)
|
514
|
+
general_error?(attr_key) ? message : "#{format_key(attr_key)} - #{message}"
|
515
|
+
end
|
516
|
+
|
490
517
|
def pointer(attr_or_relationship_name)
|
518
|
+
return '/data' if general_error?(attr_or_relationship_name)
|
491
519
|
formatted_attr_or_relationship_name = format_key(attr_or_relationship_name)
|
492
520
|
if resource_relationships.include?(attr_or_relationship_name)
|
493
521
|
"/data/relationships/#{formatted_attr_or_relationship_name}"
|
@@ -495,6 +523,10 @@ module JSONAPI
|
|
495
523
|
"/data/attributes/#{formatted_attr_or_relationship_name}"
|
496
524
|
end
|
497
525
|
end
|
526
|
+
|
527
|
+
def general_error?(attr_key)
|
528
|
+
attr_key.to_sym == :base && !resource_class._has_attribute?(attr_key)
|
529
|
+
end
|
498
530
|
end
|
499
531
|
|
500
532
|
class SaveFailed < Error
|
data/lib/jsonapi/formatter.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JSONAPI
|
2
4
|
class Formatter
|
3
5
|
class << self
|
@@ -108,7 +110,7 @@ end
|
|
108
110
|
|
109
111
|
class DasherizedKeyFormatter < JSONAPI::KeyFormatter
|
110
112
|
class << self
|
111
|
-
def format(
|
113
|
+
def format(_key)
|
112
114
|
super.underscore.dasherize
|
113
115
|
end
|
114
116
|
|
@@ -146,7 +148,7 @@ end
|
|
146
148
|
|
147
149
|
class CamelizedRouteFormatter < JSONAPI::RouteFormatter
|
148
150
|
class << self
|
149
|
-
def format(
|
151
|
+
def format(_route)
|
150
152
|
super.camelize(:lower)
|
151
153
|
end
|
152
154
|
|
@@ -158,7 +160,7 @@ end
|
|
158
160
|
|
159
161
|
class DasherizedRouteFormatter < JSONAPI::RouteFormatter
|
160
162
|
class << self
|
161
|
-
def format(
|
163
|
+
def format(_route)
|
162
164
|
super.dasherize
|
163
165
|
end
|
164
166
|
|
@@ -1,17 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JSONAPI
|
2
4
|
class IncludeDirectives
|
3
5
|
# Construct an IncludeDirectives Hash from an array of dot separated include strings.
|
4
6
|
# For example ['posts.comments.tags']
|
5
7
|
# will transform into =>
|
6
8
|
# {
|
7
|
-
# posts:{
|
8
|
-
#
|
9
|
-
# include_related:{
|
9
|
+
# posts: {
|
10
|
+
# include_related: {
|
10
11
|
# comments:{
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# include:true
|
12
|
+
# include_related: {
|
13
|
+
# tags: {
|
14
|
+
# include_related: {}
|
15
15
|
# }
|
16
16
|
# }
|
17
17
|
# }
|
@@ -19,82 +19,37 @@ module JSONAPI
|
|
19
19
|
# }
|
20
20
|
# }
|
21
21
|
|
22
|
-
def initialize(resource_klass, includes_array
|
22
|
+
def initialize(resource_klass, includes_array)
|
23
23
|
@resource_klass = resource_klass
|
24
|
-
@force_eager_load = force_eager_load
|
25
24
|
@include_directives_hash = { include_related: {} }
|
26
25
|
includes_array.each do |include|
|
27
26
|
parse_include(include)
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
|
-
def
|
32
|
-
@include_directives_hash
|
33
|
-
end
|
34
|
-
|
35
|
-
def model_includes
|
36
|
-
get_includes(@include_directives_hash)
|
37
|
-
end
|
38
|
-
|
39
|
-
def paths
|
40
|
-
delve_paths(get_includes(@include_directives_hash, false))
|
30
|
+
def [](name)
|
31
|
+
@include_directives_hash[name]
|
41
32
|
end
|
42
33
|
|
43
34
|
private
|
44
35
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
if current_resource_klass
|
52
|
-
current_relationship = current_resource_klass._relationships[fragment]
|
53
|
-
current_resource_klass = current_relationship.try(:resource_klass)
|
54
|
-
else
|
55
|
-
warn "[RELATIONSHIP NOT FOUND] Relationship could not be found for #{current_path}."
|
56
|
-
end
|
57
|
-
|
58
|
-
include_in_join = @force_eager_load || !current_relationship || current_relationship.eager_load_on_include
|
59
|
-
|
60
|
-
current[:include_related][fragment] ||= { include: false, include_related: {}, include_in_join: include_in_join }
|
61
|
-
current = current[:include_related][fragment]
|
62
|
-
end
|
63
|
-
current
|
64
|
-
end
|
65
|
-
|
66
|
-
def get_includes(directive, only_joined_includes = true)
|
67
|
-
ir = directive[:include_related]
|
68
|
-
ir = ir.select { |k,v| v[:include_in_join] } if only_joined_includes
|
36
|
+
def parse_include(include)
|
37
|
+
path = JSONAPI::Path.new(resource_klass: @resource_klass,
|
38
|
+
path_string: include,
|
39
|
+
ensure_default_field: false,
|
40
|
+
parse_fields: false)
|
69
41
|
|
70
|
-
|
71
|
-
sub = get_includes(sub_directive, only_joined_includes)
|
72
|
-
sub.any? ? { name => sub } : name
|
73
|
-
end
|
74
|
-
end
|
42
|
+
current = @include_directives_hash
|
75
43
|
|
76
|
-
|
77
|
-
|
78
|
-
local_path = ''
|
44
|
+
path.segments.each do |segment|
|
45
|
+
relationship_name = segment.relationship.name.to_sym
|
79
46
|
|
80
|
-
|
81
|
-
|
82
|
-
related = get_related(local_path)
|
83
|
-
related[:include] = true
|
47
|
+
current[:include_related][relationship_name] ||= { include_related: {} }
|
48
|
+
current = current[:include_related][relationship_name]
|
84
49
|
end
|
85
|
-
end
|
86
50
|
|
87
|
-
|
88
|
-
|
89
|
-
when Array
|
90
|
-
obj.map{|elem| delve_paths(elem)}.flatten(1)
|
91
|
-
when Hash
|
92
|
-
obj.map{|k,v| [[k]] + delve_paths(v).map{|path| [k] + path } }.flatten(1)
|
93
|
-
when Symbol, String
|
94
|
-
[[obj]]
|
95
|
-
else
|
96
|
-
raise "delve_paths cannot descend into #{obj.class.name}"
|
97
|
-
end
|
51
|
+
rescue JSONAPI::Exceptions::InvalidRelationship => _e
|
52
|
+
raise JSONAPI::Exceptions::InvalidInclude.new(@resource_klass, include)
|
98
53
|
end
|
99
54
|
end
|
100
55
|
end
|
data/lib/jsonapi/link_builder.rb
CHANGED
@@ -1,109 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JSONAPI
|
2
4
|
class LinkBuilder
|
3
5
|
attr_reader :base_url,
|
4
6
|
:primary_resource_klass,
|
5
7
|
:route_formatter,
|
6
|
-
:
|
8
|
+
:engine,
|
9
|
+
:engine_mount_point,
|
10
|
+
:url_helpers
|
11
|
+
|
12
|
+
@@url_helper_methods = {}
|
7
13
|
|
8
14
|
def initialize(config = {})
|
9
|
-
@base_url
|
15
|
+
@base_url = config[:base_url]
|
10
16
|
@primary_resource_klass = config[:primary_resource_klass]
|
11
|
-
@route_formatter
|
12
|
-
@
|
17
|
+
@route_formatter = config[:route_formatter]
|
18
|
+
@engine = build_engine
|
19
|
+
@engine_mount_point = @engine ? @engine.routes.find_script_name({}) : ""
|
13
20
|
|
14
|
-
#
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
end
|
21
|
+
# url_helpers may be either a controller which has the route helper methods, or the application router's
|
22
|
+
# url helpers module, `Rails.application.routes.url_helpers`. Because the method no longer behaves as a
|
23
|
+
# singleton, and it's expensive to generate the module, the controller is preferred.
|
24
|
+
@url_helpers = config[:url_helpers]
|
19
25
|
end
|
20
26
|
|
21
27
|
def engine?
|
22
|
-
!!@
|
28
|
+
!!@engine
|
23
29
|
end
|
24
30
|
|
25
31
|
def primary_resources_url
|
26
|
-
if
|
27
|
-
|
32
|
+
if @primary_resource_klass._routed
|
33
|
+
primary_resources_path = resources_path(primary_resource_klass)
|
34
|
+
@primary_resources_url_cached ||= "#{ base_url }#{ engine_mount_point }#{ primary_resources_path }"
|
28
35
|
else
|
29
|
-
|
36
|
+
if JSONAPI.configuration.warn_on_missing_routes && !@primary_resource_klass._warned_missing_route
|
37
|
+
warn "primary_resources_url for #{@primary_resource_klass} could not be generated"
|
38
|
+
@primary_resource_klass._warned_missing_route = true
|
39
|
+
end
|
40
|
+
nil
|
30
41
|
end
|
31
42
|
end
|
32
43
|
|
33
44
|
def query_link(query_params)
|
34
|
-
|
45
|
+
url = primary_resources_url
|
46
|
+
return url if url.nil?
|
47
|
+
"#{ url }?#{ query_params.to_query }"
|
35
48
|
end
|
36
49
|
|
37
50
|
def relationships_related_link(source, relationship, query_params = {})
|
38
|
-
|
39
|
-
|
40
|
-
|
51
|
+
if relationship._routed
|
52
|
+
url = "#{ self_link(source) }/#{ route_for_relationship(relationship) }"
|
53
|
+
url = "#{ url }?#{ query_params.to_query }" if query_params.present?
|
54
|
+
url
|
55
|
+
else
|
56
|
+
if JSONAPI.configuration.warn_on_missing_routes && !relationship._warned_missing_route
|
57
|
+
warn "related_link for #{relationship} could not be generated"
|
58
|
+
relationship._warned_missing_route = true
|
59
|
+
end
|
60
|
+
nil
|
61
|
+
end
|
41
62
|
end
|
42
63
|
|
43
64
|
def relationships_self_link(source, relationship)
|
44
|
-
|
65
|
+
if relationship._routed
|
66
|
+
"#{ self_link(source) }/relationships/#{ route_for_relationship(relationship) }"
|
67
|
+
else
|
68
|
+
if JSONAPI.configuration.warn_on_missing_routes && !relationship._warned_missing_route
|
69
|
+
warn "self_link for #{relationship} could not be generated"
|
70
|
+
relationship._warned_missing_route = true
|
71
|
+
end
|
72
|
+
nil
|
73
|
+
end
|
45
74
|
end
|
46
75
|
|
47
76
|
def self_link(source)
|
48
|
-
if
|
49
|
-
|
77
|
+
if source.class._routed
|
78
|
+
resource_url(source)
|
50
79
|
else
|
51
|
-
|
80
|
+
if JSONAPI.configuration.warn_on_missing_routes && !source.class._warned_missing_route
|
81
|
+
warn "self_link for #{source.class} could not be generated"
|
82
|
+
source.class._warned_missing_route = true
|
83
|
+
end
|
84
|
+
nil
|
52
85
|
end
|
53
86
|
end
|
54
87
|
|
55
88
|
private
|
56
89
|
|
57
|
-
def
|
90
|
+
def build_engine
|
58
91
|
scopes = module_scopes_from_class(primary_resource_klass)
|
59
92
|
|
60
93
|
begin
|
61
94
|
unless scopes.empty?
|
62
95
|
"#{ scopes.first.to_s.camelize }::Engine".safe_constantize
|
63
96
|
end
|
64
|
-
rescue LoadError => e
|
65
|
-
nil
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def engine_path_from_resource_class(klass)
|
70
|
-
path_name = engine_resources_path_name_from_class(klass)
|
71
|
-
engine_name.routes.url_helpers.public_send(path_name)
|
72
|
-
end
|
73
97
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
def engine_primary_resources_url
|
79
|
-
"#{ base_url }#{ engine_primary_resources_path }"
|
80
|
-
end
|
81
|
-
|
82
|
-
def engine_resource_path(source)
|
83
|
-
resource_path_name = engine_resource_path_name_from_source(source)
|
84
|
-
engine_name.routes.url_helpers.public_send(resource_path_name, source.id)
|
85
|
-
end
|
86
|
-
|
87
|
-
def engine_resource_path_name_from_source(source)
|
88
|
-
scopes = module_scopes_from_class(source.class)[1..-1]
|
89
|
-
base_path_name = scopes.map { |scope| scope.underscore }.join("_")
|
90
|
-
end_path_name = source.class._type.to_s.singularize
|
91
|
-
[base_path_name, end_path_name, "path"].reject(&:blank?).join("_")
|
92
|
-
end
|
93
|
-
|
94
|
-
def engine_resource_url(source)
|
95
|
-
"#{ base_url }#{ engine_resource_path(source) }"
|
96
|
-
end
|
97
|
-
|
98
|
-
def engine_resources_path_name_from_class(klass)
|
99
|
-
scopes = module_scopes_from_class(klass)[1..-1]
|
100
|
-
base_path_name = scopes.map { |scope| scope.underscore }.join("_")
|
101
|
-
end_path_name = klass._type.to_s
|
102
|
-
|
103
|
-
if base_path_name.blank?
|
104
|
-
"#{ end_path_name }_path"
|
105
|
-
else
|
106
|
-
"#{ base_path_name }_#{ end_path_name }_path"
|
98
|
+
# :nocov:
|
99
|
+
rescue LoadError => _e
|
100
|
+
nil
|
101
|
+
# :nocov:
|
107
102
|
end
|
108
103
|
end
|
109
104
|
|
@@ -112,10 +107,14 @@ module JSONAPI
|
|
112
107
|
end
|
113
108
|
|
114
109
|
def formatted_module_path_from_class(klass)
|
115
|
-
scopes =
|
110
|
+
scopes = if @engine
|
111
|
+
module_scopes_from_class(klass)[1..-1]
|
112
|
+
else
|
113
|
+
module_scopes_from_class(klass)
|
114
|
+
end
|
116
115
|
|
117
116
|
unless scopes.empty?
|
118
|
-
"/#{ scopes.map{
|
117
|
+
"/#{ scopes.map {|scope| format_route(scope.to_s.underscore)}.compact.join('/') }/"
|
119
118
|
else
|
120
119
|
"/"
|
121
120
|
end
|
@@ -125,24 +124,21 @@ module JSONAPI
|
|
125
124
|
klass.name.to_s.split("::")[0...-1]
|
126
125
|
end
|
127
126
|
|
128
|
-
def
|
129
|
-
@
|
130
|
-
|
131
|
-
|
132
|
-
def regular_primary_resources_path
|
133
|
-
regular_resources_path(primary_resource_klass)
|
127
|
+
def resources_path(source_klass)
|
128
|
+
@_resources_path ||= {}
|
129
|
+
@_resources_path[source_klass] ||= formatted_module_path_from_class(source_klass) + format_route(source_klass._type.to_s)
|
134
130
|
end
|
135
131
|
|
136
|
-
def
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
132
|
+
def resource_path(source)
|
133
|
+
if source.class.singleton?
|
134
|
+
resources_path(source.class)
|
135
|
+
else
|
136
|
+
"#{resources_path(source.class)}/#{source.id}"
|
137
|
+
end
|
142
138
|
end
|
143
139
|
|
144
|
-
def
|
145
|
-
"#{ base_url }#{
|
140
|
+
def resource_url(source)
|
141
|
+
"#{ base_url }#{ engine_mount_point }#{ resource_path(source) }"
|
146
142
|
end
|
147
143
|
|
148
144
|
def route_for_relationship(relationship)
|
data/lib/jsonapi/mime_types.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
|
3
5
|
module JSONAPI
|
@@ -7,16 +9,10 @@ module JSONAPI
|
|
7
9
|
def self.install
|
8
10
|
Mime::Type.register JSONAPI::MEDIA_TYPE, :api_json
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
)
|
15
|
-
ActionDispatch::Request.parameter_parsers = parsers
|
16
|
-
else
|
17
|
-
ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime::Type.lookup(JSONAPI::MEDIA_TYPE)] = parser
|
18
|
-
end
|
19
|
-
# :nocov:
|
12
|
+
parsers = ActionDispatch::Request.parameter_parsers.merge(
|
13
|
+
Mime::Type.lookup(JSONAPI::MEDIA_TYPE).symbol => parser
|
14
|
+
)
|
15
|
+
ActionDispatch::Request.parameter_parsers = parsers
|
20
16
|
end
|
21
17
|
|
22
18
|
def self.parser
|
data/lib/jsonapi/naive_cache.rb
CHANGED
data/lib/jsonapi/operation.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JSONAPI
|
2
4
|
class Operation
|
3
5
|
attr_reader :resource_klass, :operation_type, :options
|
@@ -8,17 +10,28 @@ module JSONAPI
|
|
8
10
|
@options = options
|
9
11
|
end
|
10
12
|
|
11
|
-
def transactional?
|
12
|
-
JSONAPI::Processor._processor_from_resource_type(resource_klass).transactional_operation_type?(operation_type)
|
13
|
-
end
|
14
|
-
|
15
13
|
def process
|
16
14
|
processor.process
|
17
15
|
end
|
18
16
|
|
19
17
|
private
|
20
18
|
def processor
|
21
|
-
|
19
|
+
self.class.processor_instance_for(resource_klass, operation_type, options)
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def processor_instance_for(resource_klass, operation_type, params)
|
24
|
+
_processor_from_resource_type(resource_klass).new(resource_klass, operation_type, params)
|
25
|
+
end
|
26
|
+
|
27
|
+
def _processor_from_resource_type(resource_klass)
|
28
|
+
processor = resource_klass.name.gsub(/Resource$/,'Processor').safe_constantize
|
29
|
+
if processor.nil?
|
30
|
+
processor = JSONAPI.configuration.default_processor_klass
|
31
|
+
end
|
32
|
+
|
33
|
+
return processor
|
34
|
+
end
|
22
35
|
end
|
23
36
|
end
|
24
37
|
end
|