actionpack 3.0.20 → 3.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- data/CHANGELOG +88 -142
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -6
- data/lib/abstract_controller.rb +1 -0
- data/lib/abstract_controller/asset_paths.rb +2 -2
- data/lib/abstract_controller/base.rb +24 -19
- data/lib/abstract_controller/callbacks.rb +19 -19
- data/lib/abstract_controller/helpers.rb +11 -13
- data/lib/abstract_controller/layouts.rb +4 -5
- data/lib/abstract_controller/railties/routes_helpers.rb +18 -0
- data/lib/abstract_controller/rendering.rb +34 -31
- data/lib/abstract_controller/url_for.rb +27 -0
- data/lib/abstract_controller/view_paths.rb +31 -6
- data/lib/action_controller.rb +5 -3
- data/lib/action_controller/base.rb +15 -16
- data/lib/action_controller/caching.rb +2 -2
- data/lib/action_controller/caching/actions.rb +11 -12
- data/lib/action_controller/caching/fragments.rb +41 -19
- data/lib/action_controller/caching/pages.rb +3 -9
- data/lib/action_controller/caching/sweeping.rb +0 -1
- data/lib/action_controller/deprecated.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +1 -1
- data/lib/action_controller/metal.rb +78 -20
- data/lib/action_controller/metal/compatibility.rb +0 -9
- data/lib/action_controller/metal/conditional_get.rb +9 -9
- data/lib/action_controller/metal/data_streaming.rb +145 -0
- data/lib/action_controller/metal/force_ssl.rb +35 -0
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +37 -44
- data/lib/action_controller/metal/hide_actions.rb +2 -3
- data/lib/action_controller/metal/http_authentication.rb +41 -38
- data/lib/action_controller/metal/implicit_render.rb +13 -13
- data/lib/action_controller/metal/instrumentation.rb +2 -2
- data/lib/action_controller/metal/mime_responds.rb +25 -19
- data/lib/action_controller/metal/params_wrapper.rb +224 -0
- data/lib/action_controller/metal/redirecting.rb +6 -2
- data/lib/action_controller/metal/renderers.rb +50 -36
- data/lib/action_controller/metal/rendering.rb +34 -25
- data/lib/action_controller/metal/request_forgery_protection.rb +18 -36
- data/lib/action_controller/metal/responder.rb +47 -12
- data/lib/action_controller/metal/streaming.rb +244 -138
- data/lib/action_controller/metal/testing.rb +0 -9
- data/lib/action_controller/metal/url_for.rb +12 -14
- data/lib/action_controller/railtie.rb +19 -37
- data/lib/action_controller/railties/paths.rb +24 -0
- data/lib/action_controller/record_identifier.rb +4 -10
- data/lib/action_controller/test_case.rb +36 -19
- data/lib/action_controller/vendor/html-scanner/html/node.rb +5 -5
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +3 -3
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -0
- data/lib/action_dispatch.rb +4 -1
- data/lib/action_dispatch/http/cache.rb +5 -32
- data/lib/action_dispatch/http/filter_parameters.rb +3 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +22 -3
- data/lib/action_dispatch/http/mime_type.rb +45 -5
- data/lib/action_dispatch/http/rack_cache.rb +58 -0
- data/lib/action_dispatch/http/request.rb +27 -41
- data/lib/action_dispatch/http/response.rb +56 -54
- data/lib/action_dispatch/http/upload.rb +1 -11
- data/lib/action_dispatch/http/url.rb +102 -42
- data/lib/action_dispatch/middleware/callbacks.rb +8 -25
- data/lib/action_dispatch/middleware/closed_error.rb +7 -0
- data/lib/action_dispatch/middleware/cookies.rb +37 -15
- data/lib/action_dispatch/middleware/flash.rb +80 -11
- data/lib/action_dispatch/middleware/params_parser.rb +2 -2
- data/lib/action_dispatch/middleware/reloader.rb +76 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +56 -226
- data/lib/action_dispatch/middleware/session/cookie_store.rb +20 -44
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -46
- data/lib/action_dispatch/middleware/show_exceptions.rb +15 -2
- data/lib/action_dispatch/middleware/stack.rb +50 -17
- data/lib/action_dispatch/middleware/static.rb +41 -29
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +2 -6
- data/lib/action_dispatch/railtie.rb +8 -0
- data/lib/action_dispatch/routing.rb +13 -1
- data/lib/action_dispatch/routing/mapper.rb +345 -227
- data/lib/action_dispatch/routing/polymorphic_routes.rb +33 -13
- data/lib/action_dispatch/routing/redirection.rb +110 -0
- data/lib/action_dispatch/routing/route.rb +15 -13
- data/lib/action_dispatch/routing/route_set.rb +116 -90
- data/lib/action_dispatch/routing/routes_proxy.rb +35 -0
- data/lib/action_dispatch/routing/url_for.rb +25 -1
- data/lib/action_dispatch/testing/assertions/response.rb +8 -10
- data/lib/action_dispatch/testing/assertions/routing.rb +15 -15
- data/lib/action_dispatch/testing/assertions/selector.rb +13 -220
- data/lib/action_dispatch/testing/integration.rb +37 -28
- data/lib/action_dispatch/testing/performance_test.rb +1 -3
- data/lib/action_dispatch/testing/test_process.rb +1 -1
- data/lib/action_dispatch/testing/test_request.rb +9 -3
- data/lib/action_dispatch/testing/test_response.rb +4 -111
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +3 -3
- data/lib/action_view.rb +39 -24
- data/lib/action_view/base.rb +61 -86
- data/lib/action_view/buffers.rb +43 -0
- data/lib/action_view/context.rb +21 -24
- data/lib/action_view/flows.rb +79 -0
- data/lib/action_view/helpers.rb +8 -6
- data/lib/action_view/helpers/active_model_helper.rb +0 -23
- data/lib/action_view/helpers/asset_paths.rb +79 -0
- data/lib/action_view/helpers/asset_tag_helper.rb +30 -500
- data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +147 -0
- data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +101 -0
- data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +200 -0
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +152 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
- data/lib/action_view/helpers/cache_helper.rb +11 -19
- data/lib/action_view/helpers/capture_helper.rb +19 -8
- data/lib/action_view/helpers/controller_helper.rb +21 -0
- data/lib/action_view/helpers/csrf_helper.rb +22 -4
- data/lib/action_view/helpers/date_helper.rb +36 -22
- data/lib/action_view/helpers/form_helper.rb +199 -113
- data/lib/action_view/helpers/form_options_helper.rb +10 -11
- data/lib/action_view/helpers/form_tag_helper.rb +94 -22
- data/lib/action_view/helpers/javascript_helper.rb +24 -107
- data/lib/action_view/helpers/number_helper.rb +36 -33
- data/lib/action_view/helpers/output_safety_helper.rb +38 -0
- data/lib/action_view/helpers/record_tag_helper.rb +6 -6
- data/lib/action_view/helpers/rendering_helper.rb +90 -0
- data/lib/action_view/helpers/sanitize_helper.rb +2 -2
- data/lib/action_view/helpers/sprockets_helper.rb +69 -0
- data/lib/action_view/helpers/tag_helper.rb +34 -12
- data/lib/action_view/helpers/text_helper.rb +30 -145
- data/lib/action_view/helpers/translation_helper.rb +10 -17
- data/lib/action_view/helpers/url_helper.rb +70 -67
- data/lib/action_view/locale/en.yml +1 -1
- data/lib/action_view/lookup_context.rb +36 -14
- data/lib/action_view/{paths.rb → path_set.rb} +9 -8
- data/lib/action_view/railtie.rb +12 -4
- data/lib/action_view/renderer/abstract_renderer.rb +36 -0
- data/lib/action_view/{render/partials.rb → renderer/partial_renderer.rb} +147 -146
- data/lib/action_view/renderer/renderer.rb +54 -0
- data/lib/action_view/renderer/streaming_template_renderer.rb +106 -0
- data/lib/action_view/renderer/template_renderer.rb +74 -0
- data/lib/action_view/template.rb +91 -54
- data/lib/action_view/template/error.rb +11 -8
- data/lib/action_view/template/handler.rb +9 -1
- data/lib/action_view/template/handlers.rb +9 -9
- data/lib/action_view/template/handlers/builder.rb +4 -4
- data/lib/action_view/template/handlers/erb.rb +21 -41
- data/lib/action_view/template/resolver.rb +171 -57
- data/lib/action_view/template/text.rb +0 -4
- data/lib/action_view/test_case.rb +32 -16
- data/lib/action_view/testing/resolvers.rb +16 -10
- data/lib/sprockets/railtie.rb +100 -0
- metadata +162 -140
- checksums.yaml +0 -7
- data/lib/action_controller/deprecated/base.rb +0 -143
- data/lib/action_controller/deprecated/dispatcher.rb +0 -28
- data/lib/action_controller/deprecated/url_writer.rb +0 -14
- data/lib/action_dispatch/routing/deprecated_mapper.rb +0 -525
- data/lib/action_view/helpers/prototype_helper.rb +0 -851
- data/lib/action_view/helpers/raw_output_helper.rb +0 -18
- data/lib/action_view/helpers/scriptaculous_helper.rb +0 -263
- data/lib/action_view/render/layouts.rb +0 -83
- data/lib/action_view/render/rendering.rb +0 -67
- data/lib/action_view/template/handlers/rjs.rb +0 -17
@@ -42,6 +42,18 @@ module ActionDispatch
|
|
42
42
|
#
|
43
43
|
# edit_polymorphic_path(@post) # => "/posts/1/edit"
|
44
44
|
# polymorphic_path(@post, :format => :pdf) # => "/posts/1.pdf"
|
45
|
+
#
|
46
|
+
# == Using with mounted engines
|
47
|
+
#
|
48
|
+
# If you use mounted engine, there is a possibility that you will need to use
|
49
|
+
# polymorphic_url pointing at engine's routes. To do that, just pass proxy used
|
50
|
+
# to reach engine's routes as a first argument:
|
51
|
+
#
|
52
|
+
# For example:
|
53
|
+
#
|
54
|
+
# polymorphic_url([blog, @post]) # it will call blog.post_path(@post)
|
55
|
+
# form_for([blog, @post]) # => "/blog/posts/1
|
56
|
+
#
|
45
57
|
module PolymorphicRoutes
|
46
58
|
# Constructs a call to a named RESTful route for the given record and returns the
|
47
59
|
# resulting URL string. For example:
|
@@ -78,19 +90,20 @@ module ActionDispatch
|
|
78
90
|
def polymorphic_url(record_or_hash_or_array, options = {})
|
79
91
|
if record_or_hash_or_array.kind_of?(Array)
|
80
92
|
record_or_hash_or_array = record_or_hash_or_array.compact
|
93
|
+
if record_or_hash_or_array.first.is_a?(ActionDispatch::Routing::RoutesProxy)
|
94
|
+
proxy = record_or_hash_or_array.shift
|
95
|
+
end
|
81
96
|
record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1
|
82
97
|
end
|
83
98
|
|
84
99
|
record = extract_record(record_or_hash_or_array)
|
85
100
|
record = record.to_model if record.respond_to?(:to_model)
|
86
101
|
|
87
|
-
args =
|
88
|
-
|
89
|
-
|
90
|
-
else [ record_or_hash_or_array ]
|
91
|
-
end
|
102
|
+
args = Array === record_or_hash_or_array ?
|
103
|
+
record_or_hash_or_array.dup :
|
104
|
+
[ record_or_hash_or_array ]
|
92
105
|
|
93
|
-
inflection = if options[:action].to_s == "new"
|
106
|
+
inflection = if options[:action] && options[:action].to_s == "new"
|
94
107
|
args.pop
|
95
108
|
:singular
|
96
109
|
elsif (record.respond_to?(:persisted?) && !record.persisted?)
|
@@ -111,7 +124,14 @@ module ActionDispatch
|
|
111
124
|
args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options
|
112
125
|
end
|
113
126
|
|
114
|
-
|
127
|
+
if proxy
|
128
|
+
proxy.send(named_route, *args)
|
129
|
+
else
|
130
|
+
# we need to use url_for, because polymorphic_url can be used in context of other than
|
131
|
+
# current routes (e.g. engine's routes). As named routes from engine are not included
|
132
|
+
# calling engine's named route directly would fail.
|
133
|
+
url_for _routes.url_helpers.__send__("hash_for_#{named_route}", *args)
|
134
|
+
end
|
115
135
|
end
|
116
136
|
|
117
137
|
# Returns the path component of a URL for the given record. It uses
|
@@ -146,24 +166,24 @@ module ActionDispatch
|
|
146
166
|
end
|
147
167
|
|
148
168
|
def build_named_route_call(records, inflection, options = {})
|
149
|
-
|
150
|
-
record = extract_record(records)
|
151
|
-
route = []
|
152
|
-
else
|
169
|
+
if records.is_a?(Array)
|
153
170
|
record = records.pop
|
154
171
|
route = records.map do |parent|
|
155
172
|
if parent.is_a?(Symbol) || parent.is_a?(String)
|
156
173
|
parent
|
157
174
|
else
|
158
|
-
ActiveModel::Naming.
|
175
|
+
ActiveModel::Naming.route_key(parent).singularize
|
159
176
|
end
|
160
177
|
end
|
178
|
+
else
|
179
|
+
record = extract_record(records)
|
180
|
+
route = []
|
161
181
|
end
|
162
182
|
|
163
183
|
if record.is_a?(Symbol) || record.is_a?(String)
|
164
184
|
route << record
|
165
185
|
else
|
166
|
-
route << ActiveModel::Naming.
|
186
|
+
route << ActiveModel::Naming.route_key(record)
|
167
187
|
route = [route.join("_").singularize] if inflection == :singular
|
168
188
|
route << "index" if ActiveModel::Naming.uncountable?(record) && inflection == :plural
|
169
189
|
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'action_dispatch/http/request'
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
module Routing
|
5
|
+
module Redirection
|
6
|
+
|
7
|
+
# Redirect any path to another path:
|
8
|
+
#
|
9
|
+
# match "/stories" => redirect("/posts")
|
10
|
+
#
|
11
|
+
# You can also use interpolation in the supplied redirect argument:
|
12
|
+
#
|
13
|
+
# match 'docs/:article', :to => redirect('/wiki/%{article}')
|
14
|
+
#
|
15
|
+
# Alternatively you can use one of the other syntaxes:
|
16
|
+
#
|
17
|
+
# The block version of redirect allows for the easy encapsulation of any logic associated with
|
18
|
+
# the redirect in question. Either the params and request are supplied as arguments, or just
|
19
|
+
# params, depending of how many arguments your block accepts. A string is required as a
|
20
|
+
# return value.
|
21
|
+
#
|
22
|
+
# match 'jokes/:number', :to => redirect do |params, request|
|
23
|
+
# path = (params[:number].to_i.even? ? "/wheres-the-beef" : "/i-love-lamp")
|
24
|
+
# "http://#{request.host_with_port}/#{path}"
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# The options version of redirect allows you to supply only the parts of the url which need
|
28
|
+
# to change, it also supports interpolation of the path similar to the first example.
|
29
|
+
#
|
30
|
+
# match 'stores/:name', :to => redirect(:subdomain => 'stores', :path => '/%{name}')
|
31
|
+
# match 'stores/:name(*all)', :to => redirect(:subdomain => 'stores', :path => '/%{name}%{all}')
|
32
|
+
#
|
33
|
+
# Finally, an object which responds to call can be supplied to redirect, allowing you to reuse
|
34
|
+
# common redirect routes. The call method must accept two arguments, params and request, and return
|
35
|
+
# a string.
|
36
|
+
#
|
37
|
+
# match 'accounts/:name' => redirect(SubdomainRedirector.new('api'))
|
38
|
+
#
|
39
|
+
def redirect(*args, &block)
|
40
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
41
|
+
status = options.delete(:status) || 301
|
42
|
+
|
43
|
+
path = args.shift
|
44
|
+
|
45
|
+
path_proc = if path.is_a?(String)
|
46
|
+
proc { |params| (params.empty? || !path.match(/%\{\w*\}/)) ? path : (path % params) }
|
47
|
+
elsif options.any?
|
48
|
+
options_proc(options)
|
49
|
+
elsif path.respond_to?(:call)
|
50
|
+
proc { |params, request| path.call(params, request) }
|
51
|
+
elsif block
|
52
|
+
block
|
53
|
+
else
|
54
|
+
raise ArgumentError, "redirection argument not supported"
|
55
|
+
end
|
56
|
+
|
57
|
+
redirection_proc(status, path_proc)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def options_proc(options)
|
63
|
+
proc do |params, request|
|
64
|
+
path = if options[:path].nil?
|
65
|
+
request.path
|
66
|
+
elsif params.empty? || !options[:path].match(/%\{\w*\}/)
|
67
|
+
options.delete(:path)
|
68
|
+
else
|
69
|
+
(options.delete(:path) % params)
|
70
|
+
end
|
71
|
+
|
72
|
+
default_options = {
|
73
|
+
:protocol => request.protocol,
|
74
|
+
:host => request.host,
|
75
|
+
:port => request.optional_port,
|
76
|
+
:path => path,
|
77
|
+
:params => request.query_parameters
|
78
|
+
}
|
79
|
+
|
80
|
+
ActionDispatch::Http::URL.url_for(options.reverse_merge(default_options))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def redirection_proc(status, path_proc)
|
85
|
+
lambda do |env|
|
86
|
+
req = Request.new(env)
|
87
|
+
|
88
|
+
params = [req.symbolized_path_parameters]
|
89
|
+
params << req if path_proc.arity > 1
|
90
|
+
|
91
|
+
uri = URI.parse(path_proc.call(*params))
|
92
|
+
uri.scheme ||= req.scheme
|
93
|
+
uri.host ||= req.host
|
94
|
+
uri.port ||= req.port unless req.standard_port?
|
95
|
+
|
96
|
+
body = %(<html><body>You are being <a href="#{ERB::Util.h(uri.to_s)}">redirected</a>.</body></html>)
|
97
|
+
|
98
|
+
headers = {
|
99
|
+
'Location' => uri.to_s,
|
100
|
+
'Content-Type' => 'text/html',
|
101
|
+
'Content-Length' => body.length.to_s
|
102
|
+
}
|
103
|
+
|
104
|
+
[ status, headers, [body] ]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/module/deprecation'
|
2
|
+
|
1
3
|
module ActionDispatch
|
2
4
|
module Routing
|
3
5
|
class Route #:nodoc:
|
@@ -10,6 +12,8 @@ module ActionDispatch
|
|
10
12
|
@defaults = defaults
|
11
13
|
@name = name
|
12
14
|
|
15
|
+
# FIXME: we should not be doing this much work in a constructor.
|
16
|
+
|
13
17
|
@requirements = requirements.merge(defaults)
|
14
18
|
@requirements.delete(:controller) if @requirements[:controller].is_a?(Regexp)
|
15
19
|
@requirements.delete_if { |k, v|
|
@@ -21,25 +25,22 @@ module ActionDispatch
|
|
21
25
|
conditions[:path_info] = ::Rack::Mount::Strexp.compile(path, requirements, SEPARATORS, anchor)
|
22
26
|
end
|
23
27
|
|
24
|
-
@
|
25
|
-
h[k] = Rack::Mount::RegexpWithNamedGroups.new(v)
|
26
|
-
h
|
27
|
-
}
|
28
|
+
@verbs = conditions[:request_method] || []
|
28
29
|
|
30
|
+
@conditions = conditions.dup
|
31
|
+
|
32
|
+
# Rack-Mount requires that :request_method be a regular expression.
|
33
|
+
# :request_method represents the HTTP verb that matches this route.
|
34
|
+
#
|
35
|
+
# Here we munge values before they get sent on to rack-mount.
|
36
|
+
@conditions[:request_method] = %r[^#{verb}$] unless @verbs.empty?
|
37
|
+
@conditions[:path_info] = Rack::Mount::RegexpWithNamedGroups.new(@conditions[:path_info]) if @conditions[:path_info]
|
29
38
|
@conditions.delete_if{ |k,v| k != :path_info && !valid_condition?(k) }
|
30
39
|
@requirements.delete_if{ |k,v| !valid_condition?(k) }
|
31
40
|
end
|
32
41
|
|
33
42
|
def verb
|
34
|
-
|
35
|
-
case method
|
36
|
-
when Regexp
|
37
|
-
source = method.source.upcase
|
38
|
-
source =~ /\A\^[-A-Z|]+\$\Z/ ? source[1..-2] : source
|
39
|
-
else
|
40
|
-
method.to_s.upcase
|
41
|
-
end
|
42
|
-
end
|
43
|
+
@verbs.join '|'
|
43
44
|
end
|
44
45
|
|
45
46
|
def segment_keys
|
@@ -49,6 +50,7 @@ module ActionDispatch
|
|
49
50
|
def to_a
|
50
51
|
[@app, @conditions, @defaults, @name]
|
51
52
|
end
|
53
|
+
deprecate :to_a
|
52
54
|
|
53
55
|
def to_s
|
54
56
|
@to_s ||= begin
|
@@ -1,17 +1,13 @@
|
|
1
1
|
require 'rack/mount'
|
2
2
|
require 'forwardable'
|
3
|
+
require 'active_support/core_ext/object/blank'
|
3
4
|
require 'active_support/core_ext/object/to_query'
|
4
|
-
require '
|
5
|
+
require 'active_support/core_ext/hash/slice'
|
6
|
+
require 'active_support/core_ext/module/remove_method'
|
5
7
|
|
6
8
|
module ActionDispatch
|
7
9
|
module Routing
|
8
10
|
class RouteSet #:nodoc:
|
9
|
-
# Since the router holds references to many parts of the system
|
10
|
-
# like engines, controllers and the application itself, inspecting
|
11
|
-
# the route set can actually be really slow, therefore we default
|
12
|
-
# alias inspect to to_s.
|
13
|
-
alias inspect to_s
|
14
|
-
|
15
11
|
PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
|
16
12
|
|
17
13
|
class Dispatcher #:nodoc:
|
@@ -56,12 +52,13 @@ module ActionDispatch
|
|
56
52
|
private
|
57
53
|
|
58
54
|
def controller_reference(controller_param)
|
55
|
+
controller_name = "#{controller_param.camelize}Controller"
|
56
|
+
|
59
57
|
unless controller = @controllers[controller_param]
|
60
|
-
controller_name = "#{controller_param.camelize}Controller"
|
61
58
|
controller = @controllers[controller_param] =
|
62
|
-
ActiveSupport::Dependencies.
|
59
|
+
ActiveSupport::Dependencies.reference(controller_name)
|
63
60
|
end
|
64
|
-
controller.get
|
61
|
+
controller.get(controller_name)
|
65
62
|
end
|
66
63
|
|
67
64
|
def dispatch(controller, action, env)
|
@@ -73,7 +70,7 @@ module ActionDispatch
|
|
73
70
|
end
|
74
71
|
|
75
72
|
def split_glob_param!(params)
|
76
|
-
params[@glob_param] = params[@glob_param].split('/').map { |v| URI.unescape(v) }
|
73
|
+
params[@glob_param] = params[@glob_param].split('/').map { |v| URI.parser.unescape(v) }
|
77
74
|
end
|
78
75
|
end
|
79
76
|
|
@@ -164,10 +161,18 @@ module ActionDispatch
|
|
164
161
|
|
165
162
|
# We use module_eval to avoid leaks
|
166
163
|
@module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
164
|
+
remove_possible_method :#{selector}
|
165
|
+
def #{selector}(*args)
|
166
|
+
options = args.extract_options!
|
167
|
+
|
168
|
+
if args.any?
|
169
|
+
options[:_positional_args] = args
|
170
|
+
options[:_positional_keys] = #{route.segment_keys.inspect}
|
171
|
+
end
|
172
|
+
|
173
|
+
options ? #{options.inspect}.merge(options) : #{options.inspect}
|
174
|
+
end
|
175
|
+
protected :#{selector}
|
171
176
|
END_EVAL
|
172
177
|
helpers << selector
|
173
178
|
end
|
@@ -190,22 +195,16 @@ module ActionDispatch
|
|
190
195
|
hash_access_method = hash_access_name(name, kind)
|
191
196
|
|
192
197
|
@module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
|
198
|
+
remove_possible_method :#{selector}
|
193
199
|
def #{selector}(*args)
|
194
|
-
|
195
|
-
|
196
|
-
if args.any?
|
197
|
-
options[:_positional_args] = args
|
198
|
-
options[:_positional_keys] = #{route.segment_keys.inspect}
|
199
|
-
end
|
200
|
-
|
201
|
-
url_for(options)
|
200
|
+
url_for(#{hash_access_method}(*args))
|
202
201
|
end
|
203
202
|
END_EVAL
|
204
203
|
helpers << selector
|
205
204
|
end
|
206
205
|
end
|
207
206
|
|
208
|
-
attr_accessor :set, :routes, :named_routes
|
207
|
+
attr_accessor :set, :routes, :named_routes, :default_scope
|
209
208
|
attr_accessor :disable_clear_and_finalize, :resources_path_names
|
210
209
|
attr_accessor :default_url_options, :request_class, :valid_conditions
|
211
210
|
|
@@ -217,7 +216,6 @@ module ActionDispatch
|
|
217
216
|
self.routes = []
|
218
217
|
self.named_routes = NamedRouteCollection.new
|
219
218
|
self.resources_path_names = self.class.default_resources_path_names.dup
|
220
|
-
self.controller_namespaces = Set.new
|
221
219
|
self.default_url_options = {}
|
222
220
|
|
223
221
|
self.request_class = request_class
|
@@ -225,27 +223,40 @@ module ActionDispatch
|
|
225
223
|
self.valid_conditions.delete(:id)
|
226
224
|
self.valid_conditions.push(:controller, :action)
|
227
225
|
|
226
|
+
@append = []
|
228
227
|
@disable_clear_and_finalize = false
|
229
228
|
clear!
|
230
229
|
end
|
231
230
|
|
232
231
|
def draw(&block)
|
233
232
|
clear! unless @disable_clear_and_finalize
|
233
|
+
eval_block(block)
|
234
|
+
finalize! unless @disable_clear_and_finalize
|
234
235
|
|
235
|
-
|
236
|
+
nil
|
237
|
+
end
|
238
|
+
|
239
|
+
def append(&block)
|
240
|
+
@append << block
|
241
|
+
end
|
242
|
+
|
243
|
+
def eval_block(block)
|
236
244
|
if block.arity == 1
|
237
|
-
|
245
|
+
raise "You are using the old router DSL which has been removed in Rails 3.1. " <<
|
246
|
+
"Please check how to update your routes file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/ " <<
|
247
|
+
"or add the rails_legacy_mapper gem to your Gemfile"
|
248
|
+
end
|
249
|
+
mapper = Mapper.new(self)
|
250
|
+
if default_scope
|
251
|
+
mapper.with_default_scope(default_scope, &block)
|
238
252
|
else
|
239
253
|
mapper.instance_exec(&block)
|
240
254
|
end
|
241
|
-
|
242
|
-
finalize! unless @disable_clear_and_finalize
|
243
|
-
|
244
|
-
nil
|
245
255
|
end
|
246
256
|
|
247
257
|
def finalize!
|
248
258
|
return if @finalized
|
259
|
+
@append.each { |blk| eval_block(blk) }
|
249
260
|
@finalized = true
|
250
261
|
@set.freeze
|
251
262
|
end
|
@@ -267,6 +278,30 @@ module ActionDispatch
|
|
267
278
|
named_routes.install(destinations, regenerate_code)
|
268
279
|
end
|
269
280
|
|
281
|
+
module MountedHelpers
|
282
|
+
end
|
283
|
+
|
284
|
+
def mounted_helpers
|
285
|
+
MountedHelpers
|
286
|
+
end
|
287
|
+
|
288
|
+
def define_mounted_helper(name)
|
289
|
+
return if MountedHelpers.method_defined?(name)
|
290
|
+
|
291
|
+
routes = self
|
292
|
+
MountedHelpers.class_eval do
|
293
|
+
define_method "_#{name}" do
|
294
|
+
RoutesProxy.new(routes, self._routes_context)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
MountedHelpers.class_eval <<-RUBY
|
299
|
+
def #{name}
|
300
|
+
@#{name} ||= _#{name}
|
301
|
+
end
|
302
|
+
RUBY
|
303
|
+
end
|
304
|
+
|
270
305
|
def url_helpers
|
271
306
|
@url_helpers ||= begin
|
272
307
|
routes = self
|
@@ -275,9 +310,9 @@ module ActionDispatch
|
|
275
310
|
extend ActiveSupport::Concern
|
276
311
|
include UrlFor
|
277
312
|
|
278
|
-
@
|
313
|
+
@_routes = routes
|
279
314
|
class << self
|
280
|
-
delegate :url_for, :to => '@
|
315
|
+
delegate :url_for, :to => '@_routes'
|
281
316
|
end
|
282
317
|
extend routes.named_routes.module
|
283
318
|
|
@@ -286,10 +321,10 @@ module ActionDispatch
|
|
286
321
|
# Yes plz - JP
|
287
322
|
included do
|
288
323
|
routes.install_helpers(self)
|
289
|
-
singleton_class.send(:
|
324
|
+
singleton_class.send(:redefine_method, :_routes) { routes }
|
290
325
|
end
|
291
326
|
|
292
|
-
define_method(:_routes) { routes }
|
327
|
+
define_method(:_routes) { @_routes || routes }
|
293
328
|
end
|
294
329
|
|
295
330
|
helpers
|
@@ -303,17 +338,29 @@ module ActionDispatch
|
|
303
338
|
def add_route(app, conditions = {}, requirements = {}, defaults = {}, name = nil, anchor = true)
|
304
339
|
raise ArgumentError, "Invalid route name: '#{name}'" unless name.blank? || name.to_s.match(/^[_a-z]\w*$/i)
|
305
340
|
route = Route.new(self, app, conditions, requirements, defaults, name, anchor)
|
306
|
-
@set.add_route(
|
341
|
+
@set.add_route(route.app, route.conditions, route.defaults, route.name)
|
307
342
|
named_routes[name] = route if name
|
308
343
|
routes << route
|
309
344
|
route
|
310
345
|
end
|
311
346
|
|
312
347
|
class Generator #:nodoc:
|
313
|
-
|
348
|
+
PARAMETERIZE = {
|
349
|
+
:parameterize => lambda do |name, value|
|
350
|
+
if name == :controller
|
351
|
+
value
|
352
|
+
elsif value.is_a?(Array)
|
353
|
+
value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
|
354
|
+
else
|
355
|
+
return nil unless param = value.to_param
|
356
|
+
param.split('/').map { |v| Rack::Mount::Utils.escape_uri(v) }.join("/")
|
357
|
+
end
|
358
|
+
end
|
359
|
+
}
|
360
|
+
|
361
|
+
attr_reader :options, :recall, :set, :named_route
|
314
362
|
|
315
363
|
def initialize(options, recall, set, extras = false)
|
316
|
-
@script_name = options.delete(:script_name)
|
317
364
|
@named_route = options.delete(:use_route)
|
318
365
|
@options = options.dup
|
319
366
|
@recall = recall.dup
|
@@ -399,34 +446,17 @@ module ActionDispatch
|
|
399
446
|
end
|
400
447
|
|
401
448
|
def generate
|
402
|
-
path, params = @set.set.generate(:path_info, named_route, options, recall,
|
449
|
+
path, params = @set.set.generate(:path_info, named_route, options, recall, PARAMETERIZE)
|
403
450
|
|
404
451
|
raise_routing_error unless path
|
405
452
|
|
406
|
-
params.reject! {|k,v| !v.to_param}
|
407
|
-
|
408
453
|
return [path, params.keys] if @extras
|
409
454
|
|
410
|
-
path
|
411
|
-
"#{script_name}#{path}"
|
455
|
+
[path, params]
|
412
456
|
rescue Rack::Mount::RoutingError
|
413
457
|
raise_routing_error
|
414
458
|
end
|
415
459
|
|
416
|
-
def opts
|
417
|
-
parameterize = lambda do |name, value|
|
418
|
-
if name == :controller
|
419
|
-
value
|
420
|
-
elsif value.is_a?(Array)
|
421
|
-
value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
|
422
|
-
else
|
423
|
-
return nil unless param = value.to_param
|
424
|
-
param.split('/').map { |v| Rack::Mount::Utils.escape_uri(v) }.join("/")
|
425
|
-
end
|
426
|
-
end
|
427
|
-
{:parameterize => parameterize}
|
428
|
-
end
|
429
|
-
|
430
460
|
def raise_routing_error
|
431
461
|
raise ActionController::RoutingError, "No route matches #{options.inspect}"
|
432
462
|
end
|
@@ -460,7 +490,12 @@ module ActionDispatch
|
|
460
490
|
Generator.new(options, recall, self, extras).generate
|
461
491
|
end
|
462
492
|
|
463
|
-
RESERVED_OPTIONS = [:
|
493
|
+
RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length,
|
494
|
+
:trailing_slash, :anchor, :params, :only_path, :script_name]
|
495
|
+
|
496
|
+
def _generate_prefix(options = {})
|
497
|
+
nil
|
498
|
+
end
|
464
499
|
|
465
500
|
def url_for(options)
|
466
501
|
finalize!
|
@@ -468,30 +503,24 @@ module ActionDispatch
|
|
468
503
|
|
469
504
|
handle_positional_args(options)
|
470
505
|
|
471
|
-
|
472
|
-
|
473
|
-
|
506
|
+
user, password = extract_authentication(options)
|
507
|
+
path_segments = options.delete(:_path_segments)
|
508
|
+
script_name = options.delete(:script_name)
|
474
509
|
|
475
|
-
|
476
|
-
rewritten_url << (options[:protocol] || "http")
|
477
|
-
rewritten_url << "://" unless rewritten_url.match("://")
|
478
|
-
rewritten_url << rewrite_authentication(options)
|
479
|
-
|
480
|
-
raise "Missing host to link to! Please provide :host parameter or set default_url_options[:host]" unless options[:host]
|
481
|
-
|
482
|
-
rewritten_url << options[:host]
|
483
|
-
rewritten_url << ":#{options.delete(:port)}" if options.key?(:port)
|
484
|
-
end
|
510
|
+
path = (script_name.blank? ? _generate_prefix(options) : script_name.chomp('/')).to_s
|
485
511
|
|
486
512
|
path_options = options.except(*RESERVED_OPTIONS)
|
487
513
|
path_options = yield(path_options) if block_given?
|
488
|
-
path = generate(path_options, path_segments || {})
|
489
514
|
|
490
|
-
|
491
|
-
|
492
|
-
rewritten_url << "##{Rack::Mount::Utils.escape_uri(options[:anchor].to_param.to_s)}" if options[:anchor]
|
515
|
+
path_addition, params = generate(path_options, path_segments || {})
|
516
|
+
path << path_addition
|
493
517
|
|
494
|
-
|
518
|
+
ActionDispatch::Http::URL.url_for(options.merge({
|
519
|
+
:path => path,
|
520
|
+
:params => params,
|
521
|
+
:user => user,
|
522
|
+
:password => password
|
523
|
+
}))
|
495
524
|
end
|
496
525
|
|
497
526
|
def call(env)
|
@@ -514,7 +543,7 @@ module ActionDispatch
|
|
514
543
|
params.each do |key, value|
|
515
544
|
if value.is_a?(String)
|
516
545
|
value = value.dup.force_encoding(Encoding::BINARY) if value.encoding_aware?
|
517
|
-
params[key] = URI.unescape(value)
|
546
|
+
params[key] = URI.parser.unescape(value)
|
518
547
|
end
|
519
548
|
end
|
520
549
|
|
@@ -533,28 +562,25 @@ module ActionDispatch
|
|
533
562
|
end
|
534
563
|
|
535
564
|
private
|
565
|
+
|
566
|
+
def extract_authentication(options)
|
567
|
+
if options[:user] && options[:password]
|
568
|
+
[options.delete(:user), options.delete(:password)]
|
569
|
+
else
|
570
|
+
nil
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
536
574
|
def handle_positional_args(options)
|
537
575
|
return unless args = options.delete(:_positional_args)
|
538
576
|
|
539
577
|
keys = options.delete(:_positional_keys)
|
540
578
|
keys -= options.keys if args.size < keys.size - 1 # take format into account
|
541
579
|
|
542
|
-
args = args.zip(keys).inject({}) do |h, (v, k)|
|
543
|
-
h[k] = v
|
544
|
-
h
|
545
|
-
end
|
546
|
-
|
547
580
|
# Tell url_for to skip default_url_options
|
548
|
-
options.merge!(args)
|
581
|
+
options.merge!(Hash[args.zip(keys).map { |v, k| [k, v] }])
|
549
582
|
end
|
550
583
|
|
551
|
-
def rewrite_authentication(options)
|
552
|
-
if options[:user] && options[:password]
|
553
|
-
"#{Rack::Utils.escape(options.delete(:user))}:#{Rack::Utils.escape(options.delete(:password))}@"
|
554
|
-
else
|
555
|
-
""
|
556
|
-
end
|
557
|
-
end
|
558
584
|
end
|
559
585
|
end
|
560
586
|
end
|