jsonapi-resources 0.10.0.beta5 → 0.10.0.beta6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/jsonapi/acts_as_resource_controller.rb +2 -1
- data/lib/jsonapi/basic_resource.rb +14 -7
- data/lib/jsonapi/configuration.rb +10 -1
- data/lib/jsonapi/link_builder.rb +78 -117
- data/lib/jsonapi/relationship.rb +6 -1
- data/lib/jsonapi/resource_controller_metal.rb +3 -0
- data/lib/jsonapi/resource_serializer.rb +2 -0
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/routing_ext.rb +8 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ac7e65d3c40e15413e9d5a7552a8f871a2313c9f9d41f4cd520ab62f8e3c7d8
|
4
|
+
data.tar.gz: 7ba4da6469f82a35eee2df2e3475d6fb28f6b229bc78863f57c5c1576cf9973e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a2ee268639e83ea3f490258f85ba8fe13785f31fd85d3a5b46cc92d7c340f3ba95f3316ca1dfcf2f33a92f31e17c023aa093d39d53b39d3c48cf8c9af22cd7ad
|
7
|
+
data.tar.gz: 76a30f8af5d5569cf40f979f296dc90e95a83f5f57b178c977ba8067755e20d5ac5e46f588f3bed4dddaf587faf7d6081e04b7116657af4d65faa6f858472a0f
|
@@ -102,7 +102,8 @@ module JSONAPI
|
|
102
102
|
base_url: base_url,
|
103
103
|
key_formatter: key_formatter,
|
104
104
|
route_formatter: route_formatter,
|
105
|
-
serialization_options: serialization_options
|
105
|
+
serialization_options: serialization_options,
|
106
|
+
controller: self
|
106
107
|
)
|
107
108
|
op.options[:cache_serializer_output] = !JSONAPI.configuration.resource_cache.nil?
|
108
109
|
|
@@ -365,7 +365,7 @@ module JSONAPI
|
|
365
365
|
|
366
366
|
@reload_needed = true
|
367
367
|
else
|
368
|
-
@model.public_send(relationship.relation_name(context: @context)).
|
368
|
+
@model.public_send(relationship.relation_name(context: @context)).delete(key)
|
369
369
|
end
|
370
370
|
|
371
371
|
:completed
|
@@ -448,6 +448,9 @@ module JSONAPI
|
|
448
448
|
end
|
449
449
|
|
450
450
|
check_reserved_resource_name(subclass._type, subclass.name)
|
451
|
+
|
452
|
+
subclass._routed = false
|
453
|
+
subclass._warned_missing_route = false
|
451
454
|
end
|
452
455
|
|
453
456
|
def rebuild_relationships(relationships)
|
@@ -494,7 +497,7 @@ module JSONAPI
|
|
494
497
|
end
|
495
498
|
end
|
496
499
|
|
497
|
-
attr_accessor :_attributes, :_relationships, :_type, :_model_hints
|
500
|
+
attr_accessor :_attributes, :_relationships, :_type, :_model_hints, :_routed, :_warned_missing_route
|
498
501
|
attr_writer :_allowed_filters, :_paginator, :_allowed_sort
|
499
502
|
|
500
503
|
def create(context)
|
@@ -960,21 +963,25 @@ module JSONAPI
|
|
960
963
|
!@immutable
|
961
964
|
end
|
962
965
|
|
963
|
-
def
|
966
|
+
def parse_exclude_links(exclude)
|
964
967
|
case exclude
|
965
968
|
when :default, "default"
|
966
|
-
|
969
|
+
[:self]
|
967
970
|
when :none, "none"
|
968
|
-
|
971
|
+
[]
|
969
972
|
when Array
|
970
|
-
|
973
|
+
exclude.collect {|link| link.to_sym}
|
971
974
|
else
|
972
975
|
fail "Invalid exclude_links"
|
973
976
|
end
|
974
977
|
end
|
975
978
|
|
979
|
+
def exclude_links(exclude)
|
980
|
+
@_exclude_links = parse_exclude_links(exclude)
|
981
|
+
end
|
982
|
+
|
976
983
|
def _exclude_links
|
977
|
-
@_exclude_links ||=
|
984
|
+
@_exclude_links ||= parse_exclude_links(JSONAPI.configuration.default_exclude_links)
|
978
985
|
end
|
979
986
|
|
980
987
|
def exclude_link?(link)
|
@@ -37,7 +37,8 @@ module JSONAPI
|
|
37
37
|
:default_caching,
|
38
38
|
:default_resource_cache_field,
|
39
39
|
:resource_cache_digest_function,
|
40
|
-
:resource_cache_usage_report_function
|
40
|
+
:resource_cache_usage_report_function,
|
41
|
+
:default_exclude_links
|
41
42
|
|
42
43
|
def initialize
|
43
44
|
#:underscored_key, :camelized_key, :dasherized_key, or custom
|
@@ -149,6 +150,12 @@ module JSONAPI
|
|
149
150
|
# Optionally provide a callable which JSONAPI will call with information about cache
|
150
151
|
# performance. Should accept three arguments: resource name, hits count, misses count.
|
151
152
|
self.resource_cache_usage_report_function = nil
|
153
|
+
|
154
|
+
# Global configuration for links exclusion
|
155
|
+
# Controls whether to generate links like `self`, `related` with all the resources
|
156
|
+
# and relationships. Accepts either `:default`, `:none`, or array containing the
|
157
|
+
# specific default links to exclude, which may be `:self` and `:related`.
|
158
|
+
self.default_exclude_links = :none
|
152
159
|
end
|
153
160
|
|
154
161
|
def cache_formatters=(bool)
|
@@ -276,6 +283,8 @@ module JSONAPI
|
|
276
283
|
attr_writer :resource_cache_digest_function
|
277
284
|
|
278
285
|
attr_writer :resource_cache_usage_report_function
|
286
|
+
|
287
|
+
attr_writer :default_exclude_links
|
279
288
|
end
|
280
289
|
|
281
290
|
class << self
|
data/lib/jsonapi/link_builder.rb
CHANGED
@@ -2,23 +2,24 @@ module JSONAPI
|
|
2
2
|
class LinkBuilder
|
3
3
|
attr_reader :base_url,
|
4
4
|
:primary_resource_klass,
|
5
|
+
:route_formatter,
|
5
6
|
:engine,
|
6
|
-
:
|
7
|
+
:engine_mount_point,
|
8
|
+
:url_helpers
|
9
|
+
|
10
|
+
@@url_helper_methods = {}
|
7
11
|
|
8
12
|
def initialize(config = {})
|
9
|
-
@base_url
|
13
|
+
@base_url = config[:base_url]
|
10
14
|
@primary_resource_klass = config[:primary_resource_klass]
|
11
|
-
@
|
12
|
-
|
13
|
-
|
14
|
-
@routes = @engine.routes
|
15
|
-
else
|
16
|
-
@routes = Rails.application.routes
|
17
|
-
end
|
15
|
+
@route_formatter = config[:route_formatter]
|
16
|
+
@engine = build_engine
|
17
|
+
@engine_mount_point = @engine ? @engine.routes.find_script_name({}) : ""
|
18
18
|
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
19
|
+
# url_helpers may be either a controller which has the route helper methods, or the application router's
|
20
|
+
# url helpers module, `Rails.application.routes.url_helpers`. Because the method no longer behaves as a
|
21
|
+
# singleton, and it's expensive to generate the module, the controller is preferred.
|
22
|
+
@url_helpers = config[:url_helpers]
|
22
23
|
end
|
23
24
|
|
24
25
|
def engine?
|
@@ -26,50 +27,60 @@ module JSONAPI
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def primary_resources_url
|
29
|
-
@
|
30
|
-
|
31
|
-
|
30
|
+
if @primary_resource_klass._routed
|
31
|
+
primary_resources_path = resources_path(primary_resource_klass)
|
32
|
+
@primary_resources_url_cached ||= "#{ base_url }#{ engine_mount_point }#{ primary_resources_path }"
|
33
|
+
else
|
34
|
+
if JSONAPI.configuration.warn_on_missing_routes && !@primary_resource_klass._warned_missing_route
|
35
|
+
warn "primary_resources_url for #{@primary_resource_klass} could not be generated"
|
36
|
+
@primary_resource_klass._warned_missing_route = true
|
37
|
+
end
|
38
|
+
nil
|
39
|
+
end
|
32
40
|
end
|
33
41
|
|
34
42
|
def query_link(query_params)
|
35
|
-
|
43
|
+
url = primary_resources_url
|
44
|
+
return url if url.nil?
|
45
|
+
"#{ url }?#{ query_params.to_query }"
|
36
46
|
end
|
37
47
|
|
38
48
|
def relationships_related_link(source, relationship, query_params = {})
|
39
|
-
if relationship.
|
40
|
-
|
41
|
-
url =
|
49
|
+
if relationship._routed
|
50
|
+
url = "#{ self_link(source) }/#{ route_for_relationship(relationship) }"
|
51
|
+
url = "#{ url }?#{ query_params.to_query }" if query_params.present?
|
52
|
+
url
|
42
53
|
else
|
43
|
-
|
44
|
-
|
54
|
+
if JSONAPI.configuration.warn_on_missing_routes && !relationship._warned_missing_route
|
55
|
+
warn "related_link for #{relationship} could not be generated"
|
56
|
+
relationship._warned_missing_route = true
|
57
|
+
end
|
58
|
+
nil
|
45
59
|
end
|
46
|
-
|
47
|
-
url = "#{ base_url }#{ url }"
|
48
|
-
url = "#{ url }?#{ query_params.to_query }" if query_params.present?
|
49
|
-
url
|
50
|
-
rescue NoMethodError
|
51
|
-
warn "related_link for #{relationship} could not be generated" if JSONAPI.configuration.warn_on_missing_routes
|
52
60
|
end
|
53
61
|
|
54
62
|
def relationships_self_link(source, relationship)
|
55
|
-
if relationship.
|
56
|
-
|
57
|
-
url = call_url_helper(url_helper_name)
|
63
|
+
if relationship._routed
|
64
|
+
"#{ self_link(source) }/relationships/#{ route_for_relationship(relationship) }"
|
58
65
|
else
|
59
|
-
|
60
|
-
|
66
|
+
if JSONAPI.configuration.warn_on_missing_routes && !relationship._warned_missing_route
|
67
|
+
warn "self_link for #{relationship} could not be generated"
|
68
|
+
relationship._warned_missing_route = true
|
69
|
+
end
|
70
|
+
nil
|
61
71
|
end
|
62
|
-
|
63
|
-
url = "#{ base_url }#{ url }"
|
64
|
-
url
|
65
|
-
rescue NoMethodError
|
66
|
-
warn "self_link for #{relationship} could not be generated" if JSONAPI.configuration.warn_on_missing_routes
|
67
72
|
end
|
68
73
|
|
69
74
|
def self_link(source)
|
70
|
-
|
71
|
-
|
72
|
-
|
75
|
+
if source.class._routed
|
76
|
+
resource_url(source)
|
77
|
+
else
|
78
|
+
if JSONAPI.configuration.warn_on_missing_routes && !source.class._warned_missing_route
|
79
|
+
warn "self_link for #{source.class} could not be generated"
|
80
|
+
source.class._warned_missing_route = true
|
81
|
+
end
|
82
|
+
nil
|
83
|
+
end
|
73
84
|
end
|
74
85
|
|
75
86
|
private
|
@@ -81,105 +92,55 @@ module JSONAPI
|
|
81
92
|
unless scopes.empty?
|
82
93
|
"#{ scopes.first.to_s.camelize }::Engine".safe_constantize
|
83
94
|
end
|
84
|
-
|
95
|
+
|
96
|
+
# :nocov:
|
85
97
|
rescue LoadError => _e
|
86
98
|
nil
|
87
|
-
|
99
|
+
# :nocov:
|
88
100
|
end
|
89
101
|
end
|
90
102
|
|
91
|
-
def
|
92
|
-
|
93
|
-
rescue NoMethodError => e
|
94
|
-
raise e
|
103
|
+
def format_route(route)
|
104
|
+
route_formatter.format(route)
|
95
105
|
end
|
96
106
|
|
97
|
-
def
|
98
|
-
|
99
|
-
|
100
|
-
|
107
|
+
def formatted_module_path_from_class(klass)
|
108
|
+
scopes = if @engine
|
109
|
+
module_scopes_from_class(klass)[1..-1]
|
110
|
+
else
|
111
|
+
module_scopes_from_class(klass)
|
112
|
+
end
|
101
113
|
|
102
|
-
|
103
|
-
|
104
|
-
if source.class.singleton?
|
105
|
-
call_url_helper(url_helper_name)
|
114
|
+
unless scopes.empty?
|
115
|
+
"/#{ scopes.map {|scope| format_route(scope.to_s.underscore)}.compact.join('/') }/"
|
106
116
|
else
|
107
|
-
|
117
|
+
"/"
|
108
118
|
end
|
109
119
|
end
|
110
120
|
|
111
|
-
def
|
112
|
-
|
121
|
+
def module_scopes_from_class(klass)
|
122
|
+
klass.name.to_s.split("::")[0...-1]
|
113
123
|
end
|
114
124
|
|
115
|
-
def
|
116
|
-
(
|
125
|
+
def resources_path(source_klass)
|
126
|
+
formatted_module_path_from_class(source_klass) + format_route(source_klass._type.to_s)
|
117
127
|
end
|
118
128
|
|
119
|
-
def
|
120
|
-
|
121
|
-
scopes = module_scopes_from_class(klass)[1..-1]
|
122
|
-
else
|
123
|
-
scopes = module_scopes_from_class(klass)
|
124
|
-
end
|
125
|
-
|
126
|
-
base_path_name = scopes.map { |scope| scope.underscore }.join("_")
|
127
|
-
end_path_name = klass._type.to_s
|
128
|
-
[base_path_name, end_path_name]
|
129
|
-
end
|
130
|
-
|
131
|
-
def resources_url_helper_name_from_class(klass)
|
132
|
-
url_helper_name_from_parts(resources_path_parts_from_class(klass))
|
133
|
-
end
|
129
|
+
def resource_path(source)
|
130
|
+
url = "#{resources_path(source.class)}"
|
134
131
|
|
135
|
-
|
136
|
-
|
137
|
-
scopes = module_scopes_from_class(klass)[1..-1]
|
138
|
-
else
|
139
|
-
scopes = module_scopes_from_class(klass)
|
132
|
+
unless source.class.singleton?
|
133
|
+
url = "#{url}/#{source.id}"
|
140
134
|
end
|
141
|
-
|
142
|
-
base_path_name = scopes.map { |scope| scope.underscore }.join("_")
|
143
|
-
end_path_name = klass._type.to_s.singularize
|
144
|
-
[base_path_name, end_path_name]
|
145
|
-
end
|
146
|
-
|
147
|
-
def resource_url_helper_name_from_source(source)
|
148
|
-
url_helper_name_from_parts(resource_path_parts_from_class(source.class))
|
149
|
-
end
|
150
|
-
|
151
|
-
def related_url_helper_name(relationship)
|
152
|
-
relationship_parts = resource_path_parts_from_class(relationship.parent_resource)
|
153
|
-
relationship_parts << "related"
|
154
|
-
relationship_parts << relationship.name
|
155
|
-
url_helper_name_from_parts(relationship_parts)
|
156
|
-
end
|
157
|
-
|
158
|
-
def singleton_related_url_helper_name(relationship)
|
159
|
-
relationship_parts = []
|
160
|
-
relationship_parts << "related"
|
161
|
-
relationship_parts << relationship.name
|
162
|
-
relationship_parts += resource_path_parts_from_class(relationship.parent_resource)
|
163
|
-
url_helper_name_from_parts(relationship_parts)
|
164
|
-
end
|
165
|
-
|
166
|
-
def relationship_self_url_helper_name(relationship)
|
167
|
-
relationship_parts = resource_path_parts_from_class(relationship.parent_resource)
|
168
|
-
relationship_parts << "relationships"
|
169
|
-
relationship_parts << relationship.name
|
170
|
-
url_helper_name_from_parts(relationship_parts)
|
135
|
+
url
|
171
136
|
end
|
172
137
|
|
173
|
-
def
|
174
|
-
|
175
|
-
relationship_parts << "relationships"
|
176
|
-
relationship_parts << relationship.name
|
177
|
-
relationship_parts += resource_path_parts_from_class(relationship.parent_resource)
|
178
|
-
url_helper_name_from_parts(relationship_parts)
|
138
|
+
def resource_url(source)
|
139
|
+
"#{ base_url }#{ engine_mount_point }#{ resource_path(source) }"
|
179
140
|
end
|
180
141
|
|
181
|
-
def
|
182
|
-
|
142
|
+
def route_for_relationship(relationship)
|
143
|
+
format_route(relationship.name)
|
183
144
|
end
|
184
145
|
end
|
185
146
|
end
|
data/lib/jsonapi/relationship.rb
CHANGED
@@ -7,6 +7,8 @@ module JSONAPI
|
|
7
7
|
|
8
8
|
attr_writer :allow_include
|
9
9
|
|
10
|
+
attr_accessor :_routed, :_warned_missing_route
|
11
|
+
|
10
12
|
def initialize(name, options = {})
|
11
13
|
@name = name.to_s
|
12
14
|
@options = options
|
@@ -27,7 +29,10 @@ module JSONAPI
|
|
27
29
|
@class_name = nil
|
28
30
|
@inverse_relationship = nil
|
29
31
|
|
30
|
-
|
32
|
+
@_routed = false
|
33
|
+
@_warned_missing_route = false
|
34
|
+
|
35
|
+
exclude_links(options.fetch(:exclude_links, JSONAPI.configuration.default_exclude_links))
|
31
36
|
|
32
37
|
# Custom methods are reserved for future use
|
33
38
|
@custom_methods = options.fetch(:custom_methods, {})
|
@@ -10,6 +10,9 @@ module JSONAPI
|
|
10
10
|
JSONAPI::ActsAsResourceController
|
11
11
|
].freeze
|
12
12
|
|
13
|
+
# Note, the url_helpers are not loaded. This will prevent links from being generated for resources, and warnings
|
14
|
+
# will be emitted. Link support can be added by including `Rails.application.routes.url_helpers`, and links
|
15
|
+
# can be disabled, and warning suppressed, for a resource with `exclude_links :default`
|
13
16
|
MODULES.each do |mod|
|
14
17
|
include mod
|
15
18
|
end
|
@@ -381,6 +381,8 @@ module JSONAPI
|
|
381
381
|
LinkBuilder.new(
|
382
382
|
base_url: options.fetch(:base_url, ''),
|
383
383
|
primary_resource_klass: primary_resource_klass,
|
384
|
+
route_formatter: options.fetch(:route_formatter, JSONAPI.configuration.route_formatter),
|
385
|
+
url_helpers: options.fetch(:url_helpers, options[:controller]),
|
384
386
|
)
|
385
387
|
end
|
386
388
|
end
|
data/lib/jsonapi/routing_ext.rb
CHANGED
@@ -20,6 +20,8 @@ module ActionDispatch
|
|
20
20
|
@resource_type = resources.first
|
21
21
|
res = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix(@resource_type))
|
22
22
|
|
23
|
+
res._routed = true
|
24
|
+
|
23
25
|
unless res.singleton?
|
24
26
|
warn "Singleton routes created for non singleton resource #{res}. Links may not be generated correctly."
|
25
27
|
end
|
@@ -84,6 +86,8 @@ module ActionDispatch
|
|
84
86
|
@resource_type = resources.first
|
85
87
|
res = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix(@resource_type))
|
86
88
|
|
89
|
+
res._routed = true
|
90
|
+
|
87
91
|
if res.singleton?
|
88
92
|
warn "Singleton resource #{res} should use `jsonapi_resource` instead."
|
89
93
|
end
|
@@ -220,6 +224,8 @@ module ActionDispatch
|
|
220
224
|
relationship_name = relationship.first
|
221
225
|
relationship = source._relationships[relationship_name]
|
222
226
|
|
227
|
+
relationship._routed = true
|
228
|
+
|
223
229
|
formatted_relationship_name = format_route(relationship.name)
|
224
230
|
|
225
231
|
if relationship.polymorphic?
|
@@ -242,6 +248,8 @@ module ActionDispatch
|
|
242
248
|
relationship_name = relationship.first
|
243
249
|
relationship = source._relationships[relationship_name]
|
244
250
|
|
251
|
+
relationship._routed = true
|
252
|
+
|
245
253
|
formatted_relationship_name = format_route(relationship.name)
|
246
254
|
related_resource = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix(relationship.class_name.underscore))
|
247
255
|
options[:controller] ||= related_resource._type.to_s
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonapi-resources
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.0.
|
4
|
+
version: 0.10.0.beta6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Gebhardt
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-07-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|