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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
module ActionController
# Rewrites URLs for Base.redirect_to and Base.url_for in the controller.
class UrlRewriter #:nodoc:
RESERVED_OPTIONS = [:anchor, :params, :path_params, :only_path, :host, :protocol]
def initialize(request, parameters)
@request, @parameters = request, parameters
@rewritten_path = @request.path ? @request.path.dup : ""
end
def rewrite(options = {})
validate_options(VALID_OPTIONS, options.keys)
rewrite_url(
rewrite_path(@rewritten_path, resolve_aliases(options)),
options
)
end
def to_s
to_str
end
def to_str
"#{@request.protocol}, #{@request.host_with_port}, #{@request.path}, #{@parameters[:controller]}, #{@parameters[:action]}, #{@request.parameters.inspect}"
end
private
def validate_options(valid_option_keys, supplied_option_keys)
unknown_option_keys = supplied_option_keys - valid_option_keys
raise(ActionController::ActionControllerError, "Unknown options: #{unknown_option_keys}") unless unknown_option_keys.empty?
end
def resolve_aliases(options)
options[:controller_prefix] = options[:module] unless options[:module].nil?
options
end
def rewrite_url(path, options)
rewritten_url = ""
rewritten_url << (options[:protocol] || @request.protocol) unless options[:only_path]
rewritten_url << (options[:host] || @request.host_with_port) unless options[:only_path]
rewritten_url << options[:application_prefix] if options[:application_prefix]
rewritten_url << path
rewritten_url << build_query_string(new_parameters(options)) if options[:params] || options[:overwrite_params]
rewritten_url << "##{options[:anchor]}" if options[:anchor]
return rewritten_url
end
def rewrite_path(options)
options = options.symbolize_keys
RESERVED_OPTIONS.each {|k| options.delete k}
path, extras = Routing::Routes.generate(options, @request)
path = "/#{path.join('/')}"
path += build_query_string(extras)
return path
end
def rewrite_path_params(path, options)
index_action = options[:action] == 'index' || options[:action].nil? && @action == 'index'
id_only = options[:path_params].size == 1 && options[:path_params]['id']
if index_action && id_only
path += '/' unless path[-1..-1] == '/'
path += "index/#{options[:path_params]['id']}"
path
else
options[:path_params].inject(path) do |path, pair|
if options[:action].nil? && @request.parameters[pair.first]
path.sub(/\b#{@request.parameters[pair.first]}\b/, pair.last.to_s)
else
path += "/#{pair.last}"
end
end
end
end
def rewrite_action(path, options)
# This regex assumes that "index" actions won't be included in the URL
all, controller_prefix, action_prefix, action_suffix =
/^\/(.*)#{@controller}\/(.*)#{@action == "index" ? "" : @action}(.*)/.match(path).to_a
if @action == "index"
if action_prefix == "index"
# we broke the parsing assumption that this would be excluded, so
# don't tell action_name about our little boo-boo
path = path.sub(action_prefix, action_name(options, nil))
elsif action_prefix && !action_prefix.empty?
path = path.sub(%r(/#{action_prefix}/?), "/" + action_name(options, action_prefix))
else
path = path.sub(%r(#{@controller}/?$), @controller + "/" + action_name(options)) # " ruby-mode
end
else
path = path.sub(
@controller + "/" + (action_prefix || "") + @action + (action_suffix || ""),
@controller + "/" + action_name(options, action_prefix)
)
end
if options[:controller_prefix] && !options[:controller]
ensure_slash_suffix(options, :controller_prefix)
if controller_prefix
path = path.sub(controller_prefix, options[:controller_prefix])
else
path = options[:controller_prefix] + path
end
end
return path
end
def rewrite_controller(path, options)
all, controller_prefix = /^\/(.*?)#{@controller}/.match(path).to_a
path = "/"
path << controller_name(options, controller_prefix)
path << action_name(options) if options[:action]
path << path_params_in_list(options) if options[:path_params]
return path
end
def action_name(options, action_prefix = nil, action_suffix = nil)
ensure_slash_suffix(options, :action_prefix)
ensure_slash_prefix(options, :action_suffix)
prefix = options[:action_prefix] || action_prefix || ""
suffix = options[:action] == "index" ? "" : (options[:action_suffix] || action_suffix || "")
name = (options[:action] == "index" ? "" : options[:action]) || ""
return prefix + name + suffix
end
def controller_name(options, controller_prefix)
ensure_slash_suffix(options, :controller_prefix)
controller_name = case options[:controller_prefix]
when String: options[:controller_prefix]
when false : ""
when nil : controller_prefix || ""
end
controller_name << (options[:controller] + "/") if options[:controller]
return controller_name
end
def path_params_in_list(options)
options[:path_params].inject("") { |path, pair| path += "/#{pair.last}" }
end
def ensure_slash_suffix(options, key)
options[key] = options[key] + "/" if options[key] && !options[key].empty? && options[key][-1..-1] != "/"
end
def ensure_slash_prefix(options, key)
options[key] = "/" + options[key] if options[key] && !options[key].empty? && options[key][0..1] != "/"
end
def include_id_in_path_params(options)
options[:path_params] = (options[:path_params] || {}).merge({"id" => options[:id]}) if options[:id]
end
def new_parameters(options)
parameters = options[:params] || existing_parameters
parameters.update(options[:overwrite_params]) if options[:overwrite_params]
parameters.reject { |key,value| value.nil? }
end
def existing_parameters
@request.parameters.reject { |key, value| %w( id action controller).include?(key) }
end
# Returns a query string with escaped keys and values from the passed hash. If the passed hash contains an "id" it'll
# be added as a path element instead of a regular parameter pair.
def build_query_string(hash)
elements = []
query_string = ""
hash.each do |key, value|
key = CGI.escape key
key += '[]' if value.class == Array
value = [ value ] unless value.class == Array
value.each { |val| elements << "#{key}=#{CGI.escape(val.to_s)}" }
end
unless elements.empty? then query_string << ("?" + elements.join("&")) end
return query_string
end
end
end
|