-
Notifications
You must be signed in to change notification settings - Fork 539
Expand file tree
/
Copy pathlink_builder.rb
More file actions
150 lines (128 loc) · 4.5 KB
/
link_builder.rb
File metadata and controls
150 lines (128 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
module JSONAPI
class LinkBuilder
attr_reader :base_url,
:primary_resource_klass,
:route_formatter,
:engine,
:engine_mount_point,
:url_helpers
@@url_helper_methods = {}
def initialize(config = {})
@base_url = config[:base_url]
@primary_resource_klass = config[:primary_resource_klass]
@route_formatter = config[:route_formatter]
@engine = build_engine
@engine_mount_point = @engine ? @engine.routes.find_script_name({}) : ""
# url_helpers may be either a controller which has the route helper methods, or the application router's
# url helpers module, `Rails.application.routes.url_helpers`. Because the method no longer behaves as a
# singleton, and it's expensive to generate the module, the controller is preferred.
@url_helpers = config[:url_helpers]
end
def engine?
!!@engine
end
def primary_resources_url
if @primary_resource_klass._routed
primary_resources_path = resources_path(primary_resource_klass)
@primary_resources_url_cached ||= "#{ base_url }#{ serialized_engine_mount_point }#{ primary_resources_path }"
else
if JSONAPI.configuration.warn_on_missing_routes && !@primary_resource_klass._warned_missing_route
warn "primary_resources_url for #{@primary_resource_klass} could not be generated"
@primary_resource_klass._warned_missing_route = true
end
nil
end
end
def query_link(query_params)
url = primary_resources_url
return url if url.nil?
"#{ url }?#{ query_params.to_query }"
end
def relationships_related_link(source, relationship, query_params = {})
if relationship._routed
url = "#{ self_link(source) }/#{ route_for_relationship(relationship) }"
url = "#{ url }?#{ query_params.to_query }" if query_params.present?
url
else
if JSONAPI.configuration.warn_on_missing_routes && !relationship._warned_missing_route
warn "related_link for #{relationship} could not be generated"
relationship._warned_missing_route = true
end
nil
end
end
def relationships_self_link(source, relationship)
if relationship._routed
"#{ self_link(source) }/relationships/#{ route_for_relationship(relationship) }"
else
if JSONAPI.configuration.warn_on_missing_routes && !relationship._warned_missing_route
warn "self_link for #{relationship} could not be generated"
relationship._warned_missing_route = true
end
nil
end
end
def self_link(source)
if source.class._routed
resource_url(source)
else
if JSONAPI.configuration.warn_on_missing_routes && !source.class._warned_missing_route
warn "self_link for #{source.class} could not be generated"
source.class._warned_missing_route = true
end
nil
end
end
private
def build_engine
scopes = module_scopes_from_class(primary_resource_klass)
begin
unless scopes.empty?
"#{ scopes.first.to_s.camelize }::Engine".safe_constantize
end
# :nocov:
rescue LoadError => _e
nil
# :nocov:
end
end
def format_route(route)
route_formatter.format(route)
end
def formatted_module_path_from_class(klass)
scopes = if @engine
module_scopes_from_class(klass)[1..-1]
else
module_scopes_from_class(klass)
end
unless scopes.empty?
"/#{ scopes.map {|scope| format_route(scope.to_s.underscore)}.compact.join('/') }/"
else
"/"
end
end
def module_scopes_from_class(klass)
klass.name.to_s.split("::")[0...-1]
end
def resources_path(source_klass)
@_resources_path ||= {}
@_resources_path[source_klass] ||= formatted_module_path_from_class(source_klass) + format_route(source_klass._type.to_s)
end
def resource_path(source)
if source.class.singleton?
resources_path(source.class)
else
"#{resources_path(source.class)}/#{source.id}"
end
end
def resource_url(source)
"#{ base_url }#{ serialized_engine_mount_point }#{ resource_path(source) }"
end
def serialized_engine_mount_point
engine_mount_point == "/" ? "" : engine_mount_point
end
def route_for_relationship(relationship)
format_route(relationship.name)
end
end
end