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
@@ -1,56 +1,17 @@
|
|
1
|
+
require 'action_dispatch/middleware/session/abstract_store'
|
2
|
+
require 'rack/session/memcache'
|
3
|
+
|
1
4
|
module ActionDispatch
|
2
5
|
module Session
|
3
|
-
class MemCacheStore <
|
6
|
+
class MemCacheStore < Rack::Session::Memcache
|
7
|
+
include Compatibility
|
8
|
+
include StaleSessionCheck
|
9
|
+
|
4
10
|
def initialize(app, options = {})
|
5
11
|
require 'memcache'
|
6
|
-
|
7
|
-
# Support old :expires option
|
8
12
|
options[:expire_after] ||= options[:expires]
|
9
|
-
|
10
|
-
super
|
11
|
-
|
12
|
-
@default_options = {
|
13
|
-
:namespace => 'rack:session',
|
14
|
-
:memcache_server => 'localhost:11211'
|
15
|
-
}.merge(@default_options)
|
16
|
-
|
17
|
-
@pool = options[:cache] || MemCache.new(@default_options[:memcache_server], @default_options)
|
18
|
-
unless @pool.servers.any? { |s| s.alive? }
|
19
|
-
raise "#{self} unable to find server during initialization."
|
20
|
-
end
|
21
|
-
@mutex = Mutex.new
|
22
|
-
|
23
13
|
super
|
24
14
|
end
|
25
|
-
|
26
|
-
private
|
27
|
-
def get_session(env, sid)
|
28
|
-
sid ||= generate_sid
|
29
|
-
begin
|
30
|
-
session = @pool.get(sid) || {}
|
31
|
-
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
|
32
|
-
session = {}
|
33
|
-
end
|
34
|
-
[sid, session]
|
35
|
-
end
|
36
|
-
|
37
|
-
def set_session(env, sid, session_data)
|
38
|
-
options = env['rack.session.options']
|
39
|
-
expiry = options[:expire_after] || 0
|
40
|
-
@pool.set(sid, session_data, expiry)
|
41
|
-
sid
|
42
|
-
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
|
43
|
-
false
|
44
|
-
end
|
45
|
-
|
46
|
-
def destroy(env)
|
47
|
-
if sid = current_session_id(env)
|
48
|
-
@pool.delete(sid)
|
49
|
-
end
|
50
|
-
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
|
51
|
-
false
|
52
|
-
end
|
53
|
-
|
54
15
|
end
|
55
16
|
end
|
56
17
|
end
|
@@ -50,7 +50,7 @@ module ActionDispatch
|
|
50
50
|
# Only this middleware cares about RoutingError. So, let's just raise
|
51
51
|
# it here.
|
52
52
|
if headers['X-Cascade'] == 'pass'
|
53
|
-
raise ActionController::RoutingError, "No route matches #{env['PATH_INFO'].inspect}"
|
53
|
+
raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}"
|
54
54
|
end
|
55
55
|
rescue Exception => exception
|
56
56
|
raise exception if env['action_dispatch.show_exceptions'] == false
|
@@ -62,6 +62,7 @@ module ActionDispatch
|
|
62
62
|
private
|
63
63
|
def render_exception(env, exception)
|
64
64
|
log_error(exception)
|
65
|
+
exception = original_exception(exception)
|
65
66
|
|
66
67
|
request = Request.new(env)
|
67
68
|
if @consider_all_requests_local || request.local?
|
@@ -115,7 +116,7 @@ module ActionDispatch
|
|
115
116
|
end
|
116
117
|
|
117
118
|
def render(status, body)
|
118
|
-
[status, {'Content-Type' =>
|
119
|
+
[status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
|
119
120
|
end
|
120
121
|
|
121
122
|
def public_path
|
@@ -154,5 +155,17 @@ module ActionDispatch
|
|
154
155
|
def logger
|
155
156
|
defined?(Rails.logger) ? Rails.logger : Logger.new($stderr)
|
156
157
|
end
|
158
|
+
|
159
|
+
def original_exception(exception)
|
160
|
+
if registered_original_exception?(exception)
|
161
|
+
exception.original_exception
|
162
|
+
else
|
163
|
+
exception
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def registered_original_exception?(exception)
|
168
|
+
exception.respond_to?(:original_exception) && @@rescue_responses.has_key?(exception.original_exception.class.name)
|
169
|
+
end
|
157
170
|
end
|
158
171
|
end
|
@@ -1,17 +1,27 @@
|
|
1
1
|
require "active_support/inflector/methods"
|
2
|
+
require "active_support/dependencies"
|
2
3
|
|
3
4
|
module ActionDispatch
|
4
|
-
class MiddlewareStack
|
5
|
+
class MiddlewareStack
|
5
6
|
class Middleware
|
6
|
-
attr_reader :args, :block
|
7
|
+
attr_reader :args, :block, :name, :classcache
|
7
8
|
|
8
9
|
def initialize(klass_or_name, *args, &block)
|
9
|
-
@
|
10
|
+
@klass = nil
|
11
|
+
|
12
|
+
if klass_or_name.respond_to?(:name)
|
13
|
+
@klass = klass_or_name
|
14
|
+
@name = @klass.name
|
15
|
+
else
|
16
|
+
@name = klass_or_name.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
@classcache = ActiveSupport::Dependencies::Reference
|
10
20
|
@args, @block = args, block
|
11
21
|
end
|
12
22
|
|
13
23
|
def klass
|
14
|
-
@
|
24
|
+
@klass || classcache[@name]
|
15
25
|
end
|
16
26
|
|
17
27
|
def ==(middleware)
|
@@ -21,7 +31,7 @@ module ActionDispatch
|
|
21
31
|
when Class
|
22
32
|
klass == middleware
|
23
33
|
else
|
24
|
-
normalize(@
|
34
|
+
normalize(@name) == normalize(middleware)
|
25
35
|
end
|
26
36
|
end
|
27
37
|
|
@@ -40,15 +50,39 @@ module ActionDispatch
|
|
40
50
|
end
|
41
51
|
end
|
42
52
|
|
43
|
-
|
44
|
-
|
45
|
-
|
53
|
+
include Enumerable
|
54
|
+
|
55
|
+
attr_accessor :middlewares
|
56
|
+
|
57
|
+
def initialize(*args)
|
58
|
+
@middlewares = []
|
59
|
+
yield(self) if block_given?
|
60
|
+
end
|
61
|
+
|
62
|
+
def each
|
63
|
+
@middlewares.each { |x| yield x }
|
64
|
+
end
|
65
|
+
|
66
|
+
def size
|
67
|
+
middlewares.size
|
68
|
+
end
|
69
|
+
|
70
|
+
def last
|
71
|
+
middlewares.last
|
72
|
+
end
|
73
|
+
|
74
|
+
def [](i)
|
75
|
+
middlewares[i]
|
76
|
+
end
|
77
|
+
|
78
|
+
def initialize_copy(other)
|
79
|
+
self.middlewares = other.middlewares.dup
|
46
80
|
end
|
47
81
|
|
48
82
|
def insert(index, *args, &block)
|
49
83
|
index = assert_index(index, :before)
|
50
84
|
middleware = self.class::Middleware.new(*args, &block)
|
51
|
-
|
85
|
+
middlewares.insert(index, middleware)
|
52
86
|
end
|
53
87
|
|
54
88
|
alias_method :insert_before, :insert
|
@@ -63,26 +97,25 @@ module ActionDispatch
|
|
63
97
|
delete(target)
|
64
98
|
end
|
65
99
|
|
66
|
-
def
|
67
|
-
|
68
|
-
push(middleware)
|
100
|
+
def delete(target)
|
101
|
+
middlewares.delete target
|
69
102
|
end
|
70
103
|
|
71
|
-
def
|
72
|
-
|
73
|
-
|
104
|
+
def use(*args, &block)
|
105
|
+
middleware = self.class::Middleware.new(*args, &block)
|
106
|
+
middlewares.push(middleware)
|
74
107
|
end
|
75
108
|
|
76
109
|
def build(app = nil, &block)
|
77
110
|
app ||= block
|
78
111
|
raise "MiddlewareStack#build requires an app" unless app
|
79
|
-
reverse.inject(app) { |a, e| e.build(a) }
|
112
|
+
middlewares.reverse.inject(app) { |a, e| e.build(a) }
|
80
113
|
end
|
81
114
|
|
82
115
|
protected
|
83
116
|
|
84
117
|
def assert_index(index, where)
|
85
|
-
i = index.is_a?(Integer) ? index :
|
118
|
+
i = index.is_a?(Integer) ? index : middlewares.index(index)
|
86
119
|
raise "No such middleware to insert #{where}: #{index.inspect}" unless i
|
87
120
|
i
|
88
121
|
end
|
@@ -1,44 +1,56 @@
|
|
1
1
|
require 'rack/utils'
|
2
2
|
|
3
3
|
module ActionDispatch
|
4
|
-
class
|
5
|
-
|
4
|
+
class FileHandler
|
5
|
+
def initialize(root, cache_control)
|
6
|
+
@root = root.chomp('/')
|
7
|
+
@compiled_root = /^#{Regexp.escape(root)}/
|
8
|
+
@file_server = ::Rack::File.new(@root, cache_control)
|
9
|
+
end
|
6
10
|
|
7
|
-
def
|
8
|
-
|
9
|
-
|
11
|
+
def match?(path)
|
12
|
+
path = path.dup
|
13
|
+
|
14
|
+
full_path = path.empty? ? @root : File.join(@root, ::Rack::Utils.unescape(path))
|
15
|
+
paths = "#{full_path}#{ext}"
|
16
|
+
|
17
|
+
matches = Dir[paths]
|
18
|
+
match = matches.detect { |m| File.file?(m) }
|
19
|
+
if match
|
20
|
+
match.sub!(@compiled_root, '')
|
21
|
+
match
|
22
|
+
end
|
10
23
|
end
|
11
24
|
|
12
25
|
def call(env)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
cached_path = directory_exist?(path) ? "#{path}/index" : path
|
21
|
-
cached_path += ::ActionController::Base.page_cache_extension
|
22
|
-
|
23
|
-
if file_exist?(cached_path)
|
24
|
-
env['PATH_INFO'] = cached_path
|
25
|
-
return @file_server.call(env)
|
26
|
-
end
|
27
|
-
end
|
26
|
+
@file_server.call(env)
|
27
|
+
end
|
28
|
+
|
29
|
+
def ext
|
30
|
+
@ext ||= begin
|
31
|
+
ext = ::ActionController::Base.page_cache_extension
|
32
|
+
"{,#{ext},/index#{ext}}"
|
28
33
|
end
|
34
|
+
end
|
35
|
+
end
|
29
36
|
|
30
|
-
|
37
|
+
class Static
|
38
|
+
def initialize(app, path, cache_control=nil)
|
39
|
+
@app = app
|
40
|
+
@file_handler = FileHandler.new(path, cache_control)
|
31
41
|
end
|
32
42
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
43
|
+
def call(env)
|
44
|
+
case env['REQUEST_METHOD']
|
45
|
+
when 'GET', 'HEAD'
|
46
|
+
path = env['PATH_INFO'].chomp('/')
|
47
|
+
if match = @file_handler.match?(path)
|
48
|
+
env["PATH_INFO"] = match
|
49
|
+
return @file_handler.call(env)
|
50
|
+
end
|
37
51
|
end
|
38
52
|
|
39
|
-
|
40
|
-
|
41
|
-
File.directory?(full_path) && File.readable?(full_path)
|
42
|
-
end
|
53
|
+
@app.call(env)
|
54
|
+
end
|
43
55
|
end
|
44
56
|
end
|
@@ -14,7 +14,7 @@
|
|
14
14
|
|
15
15
|
def debug_hash(hash)
|
16
16
|
hash.sort_by { |k, v| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
|
17
|
-
end
|
17
|
+
end unless self.class.method_defined?(:debug_hash)
|
18
18
|
%>
|
19
19
|
|
20
20
|
<h2 style="margin-top: 30px">Request</h2>
|
@@ -24,8 +24,8 @@
|
|
24
24
|
<div id="session_dump" style="display:none"><pre><%= debug_hash @request.session %></pre></div>
|
25
25
|
|
26
26
|
<p><a href="#" onclick="document.getElementById('env_dump').style.display='block'; return false;">Show env dump</a></p>
|
27
|
-
<div id="env_dump" style="display:none"><pre><%= debug_hash @request.env %></pre></div>
|
27
|
+
<div id="env_dump" style="display:none"><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></div>
|
28
28
|
|
29
29
|
|
30
30
|
<h2 style="margin-top: 30px">Response</h2>
|
31
|
-
<p><b>Headers</b>: <pre><%=h @response ? @response.headers.inspect.gsub(',', ",\n") : 'None' %></pre></p>
|
31
|
+
<p><b>Headers</b>: <pre><%=h defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %></pre></p>
|
@@ -12,14 +12,14 @@
|
|
12
12
|
<div id="traces">
|
13
13
|
<% names.each do |name| %>
|
14
14
|
<%
|
15
|
-
show = "document.getElementById('#{name.gsub
|
16
|
-
hide = (names - [name]).collect {|hide_name| "document.getElementById('#{hide_name.gsub
|
15
|
+
show = "document.getElementById('#{name.gsub(/\s/, '-')}').style.display='block';"
|
16
|
+
hide = (names - [name]).collect {|hide_name| "document.getElementById('#{hide_name.gsub(/\s/, '-')}').style.display='none';"}
|
17
17
|
%>
|
18
18
|
<a href="#" onclick="<%= hide.join %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %>
|
19
19
|
<% end %>
|
20
20
|
|
21
21
|
<% traces.each do |name, trace| %>
|
22
|
-
<div id="<%= name.gsub
|
22
|
+
<div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == "Application Trace") ? 'block' : 'none' %>;">
|
23
23
|
<pre><code><%=h trace.join "\n" %></code></pre>
|
24
24
|
</div>
|
25
25
|
<% end %>
|
@@ -1,10 +1,10 @@
|
|
1
1
|
<h1>
|
2
2
|
<%=h @exception.class.to_s %>
|
3
3
|
<% if @request.parameters['controller'] %>
|
4
|
-
in <%=h @request.parameters['controller'].
|
4
|
+
in <%=h @request.parameters['controller'].classify.pluralize %>Controller<% if @request.parameters['action'] %>#<%=h @request.parameters['action'] %><% end %>
|
5
5
|
<% end %>
|
6
6
|
</h1>
|
7
7
|
<pre><%=h @exception.message %></pre>
|
8
8
|
|
9
|
-
<%= render :
|
10
|
-
<%= render :
|
9
|
+
<%= render :template => "rescues/_trace" %>
|
10
|
+
<%= render :template => "rescues/_request_and_response" %>
|
@@ -1,11 +1,13 @@
|
|
1
|
-
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
2
3
|
<head>
|
4
|
+
<meta charset="utf-8" />
|
3
5
|
<title>Action Controller: Exception caught</title>
|
4
6
|
<style>
|
5
7
|
body { background-color: #fff; color: #333; }
|
6
8
|
|
7
9
|
body, p, ol, ul, td {
|
8
|
-
font-family: verdana, arial,
|
10
|
+
font-family: helvetica, verdana, arial, sans-serif;
|
9
11
|
font-size: 13px;
|
10
12
|
line-height: 18px;
|
11
13
|
}
|
@@ -13,9 +13,5 @@
|
|
13
13
|
|
14
14
|
<p><%=h @exception.sub_template_message %></p>
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
<%= render :file => "rescues/_trace.erb" %>
|
19
|
-
<% @exception = @real_exception %>
|
20
|
-
|
21
|
-
<%= render :file => "rescues/_request_and_response.erb" %>
|
16
|
+
<%= render :template => "rescues/_trace" %>
|
17
|
+
<%= render :template => "rescues/_request_and_response" %>
|
@@ -8,5 +8,13 @@ module ActionDispatch
|
|
8
8
|
config.action_dispatch.ip_spoofing_check = true
|
9
9
|
config.action_dispatch.show_exceptions = true
|
10
10
|
config.action_dispatch.best_standards_support = true
|
11
|
+
config.action_dispatch.tld_length = 1
|
12
|
+
config.action_dispatch.ignore_accept_header = false
|
13
|
+
config.action_dispatch.rack_cache = {:metastore => "rails:/", :entitystore => "rails:/", :verbose => true}
|
14
|
+
|
15
|
+
initializer "action_dispatch.configure" do |app|
|
16
|
+
ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length
|
17
|
+
ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header
|
18
|
+
end
|
11
19
|
end
|
12
20
|
end
|
@@ -56,6 +56,18 @@ module ActionDispatch
|
|
56
56
|
# resources :posts, :comments
|
57
57
|
# end
|
58
58
|
#
|
59
|
+
# Alternately, you can add prefixes to your path without using a separate
|
60
|
+
# directory by using +scope+. +scope+ takes additional options which
|
61
|
+
# apply to all enclosed routes.
|
62
|
+
#
|
63
|
+
# scope :path => "/cpanel", :as => 'admin' do
|
64
|
+
# resources :posts, :comments
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# For more, see <tt>Routing::Mapper::Resources#resources</tt>,
|
68
|
+
# <tt>Routing::Mapper::Scoping#namespace</tt>, and
|
69
|
+
# <tt>Routing::Mapper::Scoping#scope</tt>.
|
70
|
+
#
|
59
71
|
# == Named routes
|
60
72
|
#
|
61
73
|
# Routes can be named by passing an <tt>:as</tt> option,
|
@@ -264,10 +276,10 @@ module ActionDispatch
|
|
264
276
|
# Target specific controllers by prefixing the command with <tt>CONTROLLER=x</tt>.
|
265
277
|
#
|
266
278
|
module Routing
|
267
|
-
autoload :DeprecatedMapper, 'action_dispatch/routing/deprecated_mapper'
|
268
279
|
autoload :Mapper, 'action_dispatch/routing/mapper'
|
269
280
|
autoload :Route, 'action_dispatch/routing/route'
|
270
281
|
autoload :RouteSet, 'action_dispatch/routing/route_set'
|
282
|
+
autoload :RoutesProxy, 'action_dispatch/routing/routes_proxy'
|
271
283
|
autoload :UrlFor, 'action_dispatch/routing/url_for'
|
272
284
|
autoload :PolymorphicRoutes, 'action_dispatch/routing/polymorphic_routes'
|
273
285
|
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'erb'
|
2
2
|
require 'active_support/core_ext/hash/except'
|
3
3
|
require 'active_support/core_ext/object/blank'
|
4
|
+
require 'active_support/core_ext/object/inclusion'
|
4
5
|
require 'active_support/inflector'
|
6
|
+
require 'action_dispatch/routing/redirection'
|
5
7
|
|
6
8
|
module ActionDispatch
|
7
9
|
module Routing
|
@@ -103,10 +105,16 @@ module ActionDispatch
|
|
103
105
|
@options.reverse_merge!(:controller => /.+?/)
|
104
106
|
end
|
105
107
|
|
108
|
+
# Add a constraint for wildcard route to make it non-greedy and match the
|
109
|
+
# optional format part of the route by default
|
110
|
+
if path.match(/\*([^\/]+)$/) && @options[:format] != false
|
111
|
+
@options.reverse_merge!(:"#{$1}" => /.+?/)
|
112
|
+
end
|
113
|
+
|
106
114
|
if @options[:format] == false
|
107
115
|
@options.delete(:format)
|
108
116
|
path
|
109
|
-
elsif path.include?(":format") || path.
|
117
|
+
elsif path.include?(":format") || path.end_with?('/')
|
110
118
|
path
|
111
119
|
else
|
112
120
|
"#{path}(.:format)"
|
@@ -171,21 +179,21 @@ module ActionDispatch
|
|
171
179
|
raise ArgumentError, "missing :action"
|
172
180
|
end
|
173
181
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
182
|
+
hash = {}
|
183
|
+
hash[:controller] = controller unless controller.blank?
|
184
|
+
hash[:action] = action unless action.blank?
|
185
|
+
hash
|
178
186
|
end
|
179
187
|
end
|
180
188
|
|
181
189
|
def blocks
|
190
|
+
block = @scope[:blocks] || []
|
191
|
+
|
182
192
|
if @options[:constraints].present? && !@options[:constraints].is_a?(Hash)
|
183
|
-
block
|
184
|
-
else
|
185
|
-
block = nil
|
193
|
+
block << @options[:constraints]
|
186
194
|
end
|
187
195
|
|
188
|
-
|
196
|
+
block
|
189
197
|
end
|
190
198
|
|
191
199
|
def constraints
|
@@ -194,8 +202,8 @@ module ActionDispatch
|
|
194
202
|
|
195
203
|
def request_method_condition
|
196
204
|
if via = @options[:via]
|
197
|
-
|
198
|
-
{ :request_method =>
|
205
|
+
list = Array(via).map { |m| m.to_s.dasherize.upcase }
|
206
|
+
{ :request_method => list }
|
199
207
|
else
|
200
208
|
{ }
|
201
209
|
end
|
@@ -242,15 +250,11 @@ module ActionDispatch
|
|
242
250
|
end
|
243
251
|
|
244
252
|
module Base
|
245
|
-
def initialize(set) #:nodoc:
|
246
|
-
@set = set
|
247
|
-
end
|
248
|
-
|
249
253
|
# You can specify what Rails should route "/" to with the root method:
|
250
254
|
#
|
251
255
|
# root :to => 'pages#main'
|
252
256
|
#
|
253
|
-
# For options, see
|
257
|
+
# For options, see +match+, as +root+ uses it internally.
|
254
258
|
#
|
255
259
|
# You should put the root route at the top of <tt>config/routes.rb</tt>,
|
256
260
|
# because this means it will be matched first. As this is the most popular route
|
@@ -259,18 +263,125 @@ module ActionDispatch
|
|
259
263
|
match '/', options.reverse_merge(:as => :root)
|
260
264
|
end
|
261
265
|
|
262
|
-
#
|
263
|
-
#
|
266
|
+
# Matches a url pattern to one or more routes. Any symbols in a pattern
|
267
|
+
# are interpreted as url query parameters and thus available as +params+
|
268
|
+
# in an action:
|
269
|
+
#
|
270
|
+
# # sets :controller, :action and :id in params
|
271
|
+
# match ':controller/:action/:id'
|
272
|
+
#
|
273
|
+
# Two of these symbols are special, +:controller+ maps to the controller
|
274
|
+
# and +:action+ to the controller's action. A pattern can also map
|
275
|
+
# wildcard segments (globs) to params:
|
276
|
+
#
|
277
|
+
# match 'songs/*category/:title' => 'songs#show'
|
278
|
+
#
|
279
|
+
# # 'songs/rock/classic/stairway-to-heaven' sets
|
280
|
+
# # params[:category] = 'rock/classic'
|
281
|
+
# # params[:title] = 'stairway-to-heaven'
|
282
|
+
#
|
283
|
+
# When a pattern points to an internal route, the route's +:action+ and
|
284
|
+
# +:controller+ should be set in options or hash shorthand. Examples:
|
285
|
+
#
|
286
|
+
# match 'photos/:id' => 'photos#show'
|
287
|
+
# match 'photos/:id', :to => 'photos#show'
|
288
|
+
# match 'photos/:id', :controller => 'photos', :action => 'show'
|
289
|
+
#
|
290
|
+
# A pattern can also point to a +Rack+ endpoint i.e. anything that
|
291
|
+
# responds to +call+:
|
292
|
+
#
|
293
|
+
# match 'photos/:id' => lambda {|hash| [200, {}, "Coming soon" }
|
294
|
+
# match 'photos/:id' => PhotoRackApp
|
295
|
+
# # Yes, controller actions are just rack endpoints
|
296
|
+
# match 'photos/:id' => PhotosController.action(:show)
|
297
|
+
#
|
298
|
+
# === Options
|
299
|
+
#
|
300
|
+
# Any options not seen here are passed on as params with the url.
|
301
|
+
#
|
302
|
+
# [:controller]
|
303
|
+
# The route's controller.
|
304
|
+
#
|
305
|
+
# [:action]
|
306
|
+
# The route's action.
|
307
|
+
#
|
308
|
+
# [:path]
|
309
|
+
# The path prefix for the routes.
|
310
|
+
#
|
311
|
+
# [:module]
|
312
|
+
# The namespace for :controller.
|
313
|
+
#
|
314
|
+
# match 'path' => 'c#a', :module => 'sekret', :controller => 'posts'
|
315
|
+
# #=> Sekret::PostsController
|
316
|
+
#
|
317
|
+
# See <tt>Scoping#namespace</tt> for its scope equivalent.
|
318
|
+
#
|
319
|
+
# [:as]
|
320
|
+
# The name used to generate routing helpers.
|
321
|
+
#
|
322
|
+
# [:via]
|
323
|
+
# Allowed HTTP verb(s) for route.
|
324
|
+
#
|
325
|
+
# match 'path' => 'c#a', :via => :get
|
326
|
+
# match 'path' => 'c#a', :via => [:get, :post]
|
327
|
+
#
|
328
|
+
# [:to]
|
329
|
+
# Points to a +Rack+ endpoint. Can be an object that responds to
|
330
|
+
# +call+ or a string representing a controller's action.
|
331
|
+
#
|
332
|
+
# match 'path', :to => 'controller#action'
|
333
|
+
# match 'path', :to => lambda { [200, {}, "Success!"] }
|
334
|
+
# match 'path', :to => RackApp
|
335
|
+
#
|
336
|
+
# [:on]
|
337
|
+
# Shorthand for wrapping routes in a specific RESTful context. Valid
|
338
|
+
# values are :member, :collection, and :new. Only use within
|
339
|
+
# <tt>resource(s)</tt> block. For example:
|
340
|
+
#
|
341
|
+
# resource :bar do
|
342
|
+
# match 'foo' => 'c#a', :on => :member, :via => [:get, :post]
|
343
|
+
# end
|
344
|
+
#
|
345
|
+
# Is equivalent to:
|
346
|
+
#
|
347
|
+
# resource :bar do
|
348
|
+
# member do
|
349
|
+
# match 'foo' => 'c#a', :via => [:get, :post]
|
350
|
+
# end
|
351
|
+
# end
|
352
|
+
#
|
353
|
+
# [:constraints]
|
354
|
+
# Constrains parameters with a hash of regular expressions or an
|
355
|
+
# object that responds to #matches?
|
356
|
+
#
|
357
|
+
# match 'path/:id', :constraints => { :id => /[A-Z]\d{5}/ }
|
358
|
+
#
|
359
|
+
# class Blacklist
|
360
|
+
# def matches?(request) request.remote_ip == '1.2.3.4' end
|
361
|
+
# end
|
362
|
+
# match 'path' => 'c#a', :constraints => Blacklist.new
|
363
|
+
#
|
364
|
+
# See <tt>Scoping#constraints</tt> for more examples with its scope
|
365
|
+
# equivalent.
|
366
|
+
#
|
367
|
+
# [:defaults]
|
368
|
+
# Sets defaults for parameters
|
369
|
+
#
|
370
|
+
# # Sets params[:format] to 'jpg' by default
|
371
|
+
# match 'path' => 'c#a', :defaults => { :format => 'jpg' }
|
372
|
+
#
|
373
|
+
# See <tt>Scoping#defaults</tt> for its scope equivalent.
|
264
374
|
#
|
265
|
-
#
|
375
|
+
# [:anchor]
|
376
|
+
# Boolean to anchor a #match pattern. Default is true. When set to
|
377
|
+
# false, the pattern matches any request prefixed with the given path.
|
266
378
|
#
|
267
|
-
#
|
268
|
-
#
|
269
|
-
# action within that controller. Anything other than :controller or
|
270
|
-
# :action will be available to the action as part of params.
|
379
|
+
# # Matches any request starting with 'path'
|
380
|
+
# match 'path' => 'c#a', :anchor => false
|
271
381
|
def match(path, options=nil)
|
272
|
-
mapping = Mapping.new(@set, @scope, path, options || {})
|
273
|
-
|
382
|
+
mapping = Mapping.new(@set, @scope, path, options || {})
|
383
|
+
app, conditions, requirements, defaults, as, anchor = mapping.to_route
|
384
|
+
@set.add_route(app, conditions, requirements, defaults, as, anchor)
|
274
385
|
self
|
275
386
|
end
|
276
387
|
|
@@ -282,6 +393,8 @@ module ActionDispatch
|
|
282
393
|
#
|
283
394
|
# mount(SomeRackApp => "some_route")
|
284
395
|
#
|
396
|
+
# For options, see +match+, as +mount+ uses it internally.
|
397
|
+
#
|
285
398
|
# All mounted applications come with routing helpers to access them.
|
286
399
|
# These are named after the class specified, so for the above example
|
287
400
|
# the helper is either +some_rack_app_path+ or +some_rack_app_url+.
|
@@ -302,7 +415,11 @@ module ActionDispatch
|
|
302
415
|
|
303
416
|
raise "A rack application must be specified" unless path
|
304
417
|
|
418
|
+
options[:as] ||= app_name(app)
|
419
|
+
|
305
420
|
match(path, options.merge(:to => app, :anchor => false, :format => false))
|
421
|
+
|
422
|
+
define_generate_prefix(app, options[:as])
|
306
423
|
self
|
307
424
|
end
|
308
425
|
|
@@ -310,11 +427,45 @@ module ActionDispatch
|
|
310
427
|
@set.default_url_options = options
|
311
428
|
end
|
312
429
|
alias_method :default_url_options, :default_url_options=
|
430
|
+
|
431
|
+
def with_default_scope(scope, &block)
|
432
|
+
scope(scope) do
|
433
|
+
instance_exec(&block)
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
private
|
438
|
+
def app_name(app)
|
439
|
+
return unless app.respond_to?(:routes)
|
440
|
+
|
441
|
+
if app.respond_to?(:railtie_name)
|
442
|
+
app.railtie_name
|
443
|
+
else
|
444
|
+
class_name = app.class.is_a?(Class) ? app.name : app.class.name
|
445
|
+
ActiveSupport::Inflector.underscore(class_name).gsub("/", "_")
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
def define_generate_prefix(app, name)
|
450
|
+
return unless app.respond_to?(:routes) && app.routes.respond_to?(:define_mounted_helper)
|
451
|
+
|
452
|
+
_route = @set.named_routes.routes[name.to_sym]
|
453
|
+
_routes = @set
|
454
|
+
app.routes.define_mounted_helper(name)
|
455
|
+
app.routes.class_eval do
|
456
|
+
define_method :_generate_prefix do |options|
|
457
|
+
prefix_options = options.slice(*_route.segment_keys)
|
458
|
+
# we must actually delete prefix segment keys to avoid passing them to next url_for
|
459
|
+
_route.segment_keys.each { |k| options.delete(k) }
|
460
|
+
_routes.url_helpers.send("#{name}_path", prefix_options)
|
461
|
+
end
|
462
|
+
end
|
463
|
+
end
|
313
464
|
end
|
314
465
|
|
315
466
|
module HttpHelpers
|
316
467
|
# Define a route that only recognizes HTTP GET.
|
317
|
-
# For supported arguments, see
|
468
|
+
# For supported arguments, see <tt>Base#match</tt>.
|
318
469
|
#
|
319
470
|
# Example:
|
320
471
|
#
|
@@ -324,7 +475,7 @@ module ActionDispatch
|
|
324
475
|
end
|
325
476
|
|
326
477
|
# Define a route that only recognizes HTTP POST.
|
327
|
-
# For supported arguments, see
|
478
|
+
# For supported arguments, see <tt>Base#match</tt>.
|
328
479
|
#
|
329
480
|
# Example:
|
330
481
|
#
|
@@ -334,7 +485,7 @@ module ActionDispatch
|
|
334
485
|
end
|
335
486
|
|
336
487
|
# Define a route that only recognizes HTTP PUT.
|
337
|
-
# For supported arguments, see
|
488
|
+
# For supported arguments, see <tt>Base#match</tt>.
|
338
489
|
#
|
339
490
|
# Example:
|
340
491
|
#
|
@@ -344,7 +495,7 @@ module ActionDispatch
|
|
344
495
|
end
|
345
496
|
|
346
497
|
# Define a route that only recognizes HTTP PUT.
|
347
|
-
# For supported arguments, see
|
498
|
+
# For supported arguments, see <tt>Base#match</tt>.
|
348
499
|
#
|
349
500
|
# Example:
|
350
501
|
#
|
@@ -353,39 +504,6 @@ module ActionDispatch
|
|
353
504
|
map_method(:delete, *args, &block)
|
354
505
|
end
|
355
506
|
|
356
|
-
# Redirect any path to another path:
|
357
|
-
#
|
358
|
-
# match "/stories" => redirect("/posts")
|
359
|
-
def redirect(*args, &block)
|
360
|
-
options = args.last.is_a?(Hash) ? args.pop : {}
|
361
|
-
|
362
|
-
path = args.shift || block
|
363
|
-
path_proc = path.is_a?(Proc) ? path : proc { |params| path % params }
|
364
|
-
status = options[:status] || 301
|
365
|
-
|
366
|
-
lambda do |env|
|
367
|
-
req = Request.new(env)
|
368
|
-
|
369
|
-
params = [req.symbolized_path_parameters]
|
370
|
-
params << req if path_proc.arity > 1
|
371
|
-
|
372
|
-
uri = URI.parse(path_proc.call(*params))
|
373
|
-
uri.scheme ||= req.scheme
|
374
|
-
uri.host ||= req.host
|
375
|
-
uri.port ||= req.port unless req.standard_port?
|
376
|
-
|
377
|
-
body = %(<html><body>You are being <a href="#{ERB::Util.h(uri.to_s)}">redirected</a>.</body></html>)
|
378
|
-
|
379
|
-
headers = {
|
380
|
-
'Location' => uri.to_s,
|
381
|
-
'Content-Type' => 'text/html',
|
382
|
-
'Content-Length' => body.length.to_s
|
383
|
-
}
|
384
|
-
|
385
|
-
[ status, headers, [body] ]
|
386
|
-
end
|
387
|
-
end
|
388
|
-
|
389
507
|
private
|
390
508
|
def map_method(method, *args, &block)
|
391
509
|
options = args.extract_options!
|
@@ -405,58 +523,53 @@ module ActionDispatch
|
|
405
523
|
# namespace "admin" do
|
406
524
|
# resources :posts, :comments
|
407
525
|
# end
|
408
|
-
#
|
526
|
+
#
|
409
527
|
# This will create a number of routes for each of the posts and comments
|
410
528
|
# controller. For Admin::PostsController, Rails will create:
|
411
|
-
#
|
412
|
-
# GET /admin/
|
413
|
-
# GET /admin/
|
414
|
-
# POST /admin/
|
415
|
-
# GET /admin/
|
416
|
-
# GET /admin/
|
417
|
-
# PUT /admin/
|
418
|
-
# DELETE /admin/
|
419
|
-
#
|
420
|
-
# If you want to route /
|
529
|
+
#
|
530
|
+
# GET /admin/posts
|
531
|
+
# GET /admin/posts/new
|
532
|
+
# POST /admin/posts
|
533
|
+
# GET /admin/posts/1
|
534
|
+
# GET /admin/posts/1/edit
|
535
|
+
# PUT /admin/posts/1
|
536
|
+
# DELETE /admin/posts/1
|
537
|
+
#
|
538
|
+
# If you want to route /posts (without the prefix /admin) to
|
421
539
|
# Admin::PostsController, you could use
|
422
|
-
#
|
540
|
+
#
|
423
541
|
# scope :module => "admin" do
|
424
|
-
# resources :posts
|
542
|
+
# resources :posts
|
425
543
|
# end
|
426
544
|
#
|
427
545
|
# or, for a single case
|
428
|
-
#
|
546
|
+
#
|
429
547
|
# resources :posts, :module => "admin"
|
430
|
-
#
|
431
|
-
# If you want to route /admin/
|
548
|
+
#
|
549
|
+
# If you want to route /admin/posts to PostsController
|
432
550
|
# (without the Admin:: module prefix), you could use
|
433
|
-
#
|
551
|
+
#
|
434
552
|
# scope "/admin" do
|
435
|
-
# resources :posts
|
553
|
+
# resources :posts
|
436
554
|
# end
|
437
555
|
#
|
438
556
|
# or, for a single case
|
439
|
-
#
|
440
|
-
# resources :posts, :path => "/admin
|
557
|
+
#
|
558
|
+
# resources :posts, :path => "/admin"
|
441
559
|
#
|
442
560
|
# In each of these cases, the named routes remain the same as if you did
|
443
561
|
# not use scope. In the last case, the following paths map to
|
444
562
|
# PostsController:
|
445
|
-
#
|
446
|
-
# GET /admin/
|
447
|
-
# GET /admin/
|
448
|
-
# POST /admin/
|
449
|
-
# GET /admin/
|
450
|
-
# GET /admin/
|
451
|
-
# PUT /admin/
|
452
|
-
# DELETE /admin/
|
563
|
+
#
|
564
|
+
# GET /admin/posts
|
565
|
+
# GET /admin/posts/new
|
566
|
+
# POST /admin/posts
|
567
|
+
# GET /admin/posts/1
|
568
|
+
# GET /admin/posts/1/edit
|
569
|
+
# PUT /admin/posts/1
|
570
|
+
# DELETE /admin/posts/1
|
453
571
|
module Scoping
|
454
|
-
|
455
|
-
@scope = {}
|
456
|
-
super
|
457
|
-
end
|
458
|
-
|
459
|
-
# Used to scope a set of routes to particular constraints.
|
572
|
+
# Scopes a set of routes to the given default options.
|
460
573
|
#
|
461
574
|
# Take the following route definition as an example:
|
462
575
|
#
|
@@ -468,60 +581,30 @@ module ActionDispatch
|
|
468
581
|
# The difference here being that the routes generated are like /rails/projects/2,
|
469
582
|
# rather than /accounts/rails/projects/2.
|
470
583
|
#
|
471
|
-
# ===
|
472
|
-
# [:module]
|
473
|
-
# If you want to route /posts (without the prefix /admin) to
|
474
|
-
# Admin::PostsController, you could use
|
475
|
-
#
|
476
|
-
# scope :module => "admin" do
|
477
|
-
# resources :posts
|
478
|
-
# end
|
479
|
-
#
|
480
|
-
# [:path]
|
481
|
-
# If you want to prefix the route, you could use
|
482
|
-
#
|
483
|
-
# scope :path => "/admin" do
|
484
|
-
# resources :posts
|
485
|
-
# end
|
486
|
-
#
|
487
|
-
# This will prefix all of the +posts+ resource's requests with '/admin'
|
488
|
-
#
|
489
|
-
# [:as]
|
490
|
-
# Prefixes the routing helpers in this scope with the specified label.
|
584
|
+
# === Options
|
491
585
|
#
|
492
|
-
#
|
493
|
-
# resources :posts
|
494
|
-
# end
|
495
|
-
#
|
496
|
-
# Helpers such as +posts_path+ will now be +sekret_posts_path+
|
497
|
-
#
|
498
|
-
# [:shallow_path]
|
586
|
+
# Takes same options as <tt>Base#match</tt> and <tt>Resources#resources</tt>.
|
499
587
|
#
|
500
|
-
#
|
588
|
+
# === Examples
|
501
589
|
#
|
502
|
-
#
|
503
|
-
#
|
504
|
-
#
|
505
|
-
#
|
590
|
+
# # route /posts (without the prefix /admin) to Admin::PostsController
|
591
|
+
# scope :module => "admin" do
|
592
|
+
# resources :posts
|
593
|
+
# end
|
506
594
|
#
|
507
|
-
#
|
595
|
+
# # prefix the posts resource's requests with '/admin'
|
596
|
+
# scope :path => "/admin" do
|
597
|
+
# resources :posts
|
598
|
+
# end
|
508
599
|
#
|
509
|
-
#
|
510
|
-
#
|
511
|
-
#
|
512
|
-
#
|
513
|
-
# comment GET /sekret/comments/:id(.:format)
|
514
|
-
# comment PUT /sekret/comments/:id(.:format)
|
515
|
-
# comment DELETE /sekret/comments/:id(.:format)
|
600
|
+
# # prefix the routing helper name: sekret_posts_path instead of posts_path
|
601
|
+
# scope :as => "sekret" do
|
602
|
+
# resources :posts
|
603
|
+
# end
|
516
604
|
def scope(*args)
|
517
605
|
options = args.extract_options!
|
518
606
|
options = options.dup
|
519
607
|
|
520
|
-
if name_prefix = options.delete(:name_prefix)
|
521
|
-
options[:as] ||= name_prefix
|
522
|
-
ActiveSupport::Deprecation.warn ":name_prefix was deprecated in the new router syntax. Use :as instead.", caller
|
523
|
-
end
|
524
|
-
|
525
608
|
options[:path] = args.first if args.first.is_a?(String)
|
526
609
|
recover = {}
|
527
610
|
|
@@ -580,50 +663,38 @@ module ActionDispatch
|
|
580
663
|
# admin_post GET /admin/posts/:id(.:format) {:action=>"show", :controller=>"admin/posts"}
|
581
664
|
# admin_post PUT /admin/posts/:id(.:format) {:action=>"update", :controller=>"admin/posts"}
|
582
665
|
# admin_post DELETE /admin/posts/:id(.:format) {:action=>"destroy", :controller=>"admin/posts"}
|
583
|
-
# === Supported options
|
584
666
|
#
|
585
|
-
#
|
667
|
+
# === Options
|
586
668
|
#
|
587
|
-
#
|
588
|
-
#
|
669
|
+
# The +:path+, +:as+, +:module+, +:shallow_path+ and +:shallow_prefix+
|
670
|
+
# options all default to the name of the namespace.
|
589
671
|
#
|
590
|
-
#
|
591
|
-
#
|
592
|
-
# end
|
672
|
+
# For options, see <tt>Base#match</tt>. For +:shallow_path+ option, see
|
673
|
+
# <tt>Resources#resources</tt>.
|
593
674
|
#
|
594
|
-
#
|
675
|
+
# === Examples
|
595
676
|
#
|
596
|
-
#
|
597
|
-
#
|
598
|
-
#
|
599
|
-
#
|
600
|
-
# resources :posts
|
601
|
-
# end
|
602
|
-
#
|
603
|
-
# The +PostsController+ here should go in the +Sekret+ namespace and so it should be defined like this:
|
604
|
-
#
|
605
|
-
# class Sekret::PostsController < ApplicationController
|
606
|
-
# # code go here
|
607
|
-
# end
|
608
|
-
#
|
609
|
-
# [:as]
|
610
|
-
# Changes the name used in routing helpers for this namespace.
|
611
|
-
#
|
612
|
-
# namespace :admin, :as => "sekret" do
|
613
|
-
# resources :posts
|
614
|
-
# end
|
677
|
+
# # accessible through /sekret/posts rather than /admin/posts
|
678
|
+
# namespace :admin, :path => "sekret" do
|
679
|
+
# resources :posts
|
680
|
+
# end
|
615
681
|
#
|
616
|
-
#
|
682
|
+
# # maps to Sekret::PostsController rather than Admin::PostsController
|
683
|
+
# namespace :admin, :module => "sekret" do
|
684
|
+
# resources :posts
|
685
|
+
# end
|
617
686
|
#
|
618
|
-
#
|
619
|
-
#
|
687
|
+
# # generates sekret_posts_path rather than admin_posts_path
|
688
|
+
# namespace :admin, :as => "sekret" do
|
689
|
+
# resources :posts
|
690
|
+
# end
|
620
691
|
def namespace(path, options = {})
|
621
692
|
path = path.to_s
|
622
693
|
options = { :path => path, :as => path, :module => path,
|
623
694
|
:shallow_path => path, :shallow_prefix => path }.merge!(options)
|
624
695
|
scope(options) { yield }
|
625
696
|
end
|
626
|
-
|
697
|
+
|
627
698
|
# === Parameter Restriction
|
628
699
|
# Allows you to constrain the nested routes based on a set of rules.
|
629
700
|
# For instance, in order to change the routes to allow for a dot character in the +id+ parameter:
|
@@ -634,8 +705,8 @@ module ActionDispatch
|
|
634
705
|
#
|
635
706
|
# Now routes such as +/posts/1+ will no longer be valid, but +/posts/1.1+ will be.
|
636
707
|
# The +id+ parameter must match the constraint passed in for this example.
|
637
|
-
#
|
638
|
-
# You may use this to also
|
708
|
+
#
|
709
|
+
# You may use this to also restrict other parameters:
|
639
710
|
#
|
640
711
|
# resources :posts do
|
641
712
|
# constraints(:post_id => /\d+\.\d+) do
|
@@ -655,7 +726,7 @@ module ActionDispatch
|
|
655
726
|
#
|
656
727
|
# === Dynamic request matching
|
657
728
|
#
|
658
|
-
# Requests to routes can be constrained based on specific
|
729
|
+
# Requests to routes can be constrained based on specific criteria:
|
659
730
|
#
|
660
731
|
# constraints(lambda { |req| req.env["HTTP_USER_AGENT"] =~ /iPhone/ }) do
|
661
732
|
# resources :iphones
|
@@ -683,70 +754,70 @@ module ActionDispatch
|
|
683
754
|
end
|
684
755
|
|
685
756
|
# Allows you to set default parameters for a route, such as this:
|
686
|
-
#
|
687
|
-
#
|
688
|
-
#
|
757
|
+
# defaults :id => 'home' do
|
758
|
+
# match 'scoped_pages/(:id)', :to => 'pages#show'
|
759
|
+
# end
|
689
760
|
# Using this, the +:id+ parameter here will default to 'home'.
|
690
761
|
def defaults(defaults = {})
|
691
762
|
scope(:defaults => defaults) { yield }
|
692
763
|
end
|
693
764
|
|
694
765
|
private
|
695
|
-
def scope_options
|
766
|
+
def scope_options #:nodoc:
|
696
767
|
@scope_options ||= private_methods.grep(/^merge_(.+)_scope$/) { $1.to_sym }
|
697
768
|
end
|
698
769
|
|
699
|
-
def merge_path_scope(parent, child)
|
770
|
+
def merge_path_scope(parent, child) #:nodoc:
|
700
771
|
Mapper.normalize_path("#{parent}/#{child}")
|
701
772
|
end
|
702
773
|
|
703
|
-
def merge_shallow_path_scope(parent, child)
|
774
|
+
def merge_shallow_path_scope(parent, child) #:nodoc:
|
704
775
|
Mapper.normalize_path("#{parent}/#{child}")
|
705
776
|
end
|
706
777
|
|
707
|
-
def merge_as_scope(parent, child)
|
778
|
+
def merge_as_scope(parent, child) #:nodoc:
|
708
779
|
parent ? "#{parent}_#{child}" : child
|
709
780
|
end
|
710
781
|
|
711
|
-
def merge_shallow_prefix_scope(parent, child)
|
782
|
+
def merge_shallow_prefix_scope(parent, child) #:nodoc:
|
712
783
|
parent ? "#{parent}_#{child}" : child
|
713
784
|
end
|
714
785
|
|
715
|
-
def merge_module_scope(parent, child)
|
786
|
+
def merge_module_scope(parent, child) #:nodoc:
|
716
787
|
parent ? "#{parent}/#{child}" : child
|
717
788
|
end
|
718
789
|
|
719
|
-
def merge_controller_scope(parent, child)
|
790
|
+
def merge_controller_scope(parent, child) #:nodoc:
|
720
791
|
child
|
721
792
|
end
|
722
793
|
|
723
|
-
def merge_path_names_scope(parent, child)
|
794
|
+
def merge_path_names_scope(parent, child) #:nodoc:
|
724
795
|
merge_options_scope(parent, child)
|
725
796
|
end
|
726
797
|
|
727
|
-
def merge_constraints_scope(parent, child)
|
798
|
+
def merge_constraints_scope(parent, child) #:nodoc:
|
728
799
|
merge_options_scope(parent, child)
|
729
800
|
end
|
730
801
|
|
731
|
-
def merge_defaults_scope(parent, child)
|
802
|
+
def merge_defaults_scope(parent, child) #:nodoc:
|
732
803
|
merge_options_scope(parent, child)
|
733
804
|
end
|
734
805
|
|
735
|
-
def merge_blocks_scope(parent, child)
|
806
|
+
def merge_blocks_scope(parent, child) #:nodoc:
|
736
807
|
merged = parent ? parent.dup : []
|
737
808
|
merged << child if child
|
738
809
|
merged
|
739
810
|
end
|
740
811
|
|
741
|
-
def merge_options_scope(parent, child)
|
812
|
+
def merge_options_scope(parent, child) #:nodoc:
|
742
813
|
(parent || {}).except(*override_keys(child)).merge(child)
|
743
814
|
end
|
744
815
|
|
745
|
-
def merge_shallow_scope(parent, child)
|
816
|
+
def merge_shallow_scope(parent, child) #:nodoc:
|
746
817
|
child ? true : false
|
747
818
|
end
|
748
819
|
|
749
|
-
def override_keys(child)
|
820
|
+
def override_keys(child) #:nodoc:
|
750
821
|
child.key?(:only) || child.key?(:except) ? [:only, :except] : []
|
751
822
|
end
|
752
823
|
end
|
@@ -838,7 +909,8 @@ module ActionDispatch
|
|
838
909
|
|
839
910
|
alias :member_name :singular
|
840
911
|
|
841
|
-
# Checks for uncountable plurals, and appends "_index" if
|
912
|
+
# Checks for uncountable plurals, and appends "_index" if the plural
|
913
|
+
# and singular form are the same.
|
842
914
|
def collection_name
|
843
915
|
singular == plural ? "#{plural}_index" : plural
|
844
916
|
end
|
@@ -867,6 +939,7 @@ module ActionDispatch
|
|
867
939
|
DEFAULT_ACTIONS = [:show, :create, :update, :destroy, :new, :edit]
|
868
940
|
|
869
941
|
def initialize(entities, options)
|
942
|
+
@as = nil
|
870
943
|
@name = entities.to_s
|
871
944
|
@path = (options.delete(:path) || @name).to_s
|
872
945
|
@controller = (options.delete(:controller) || plural).to_s
|
@@ -889,11 +962,6 @@ module ActionDispatch
|
|
889
962
|
alias :nested_scope :path
|
890
963
|
end
|
891
964
|
|
892
|
-
def initialize(*args) #:nodoc:
|
893
|
-
super
|
894
|
-
@scope[:path_names] = @set.resources_path_names
|
895
|
-
end
|
896
|
-
|
897
965
|
def resources_path_names(options)
|
898
966
|
@scope[:path_names].merge!(options)
|
899
967
|
end
|
@@ -916,6 +984,9 @@ module ActionDispatch
|
|
916
984
|
# GET /geocoder/edit
|
917
985
|
# PUT /geocoder
|
918
986
|
# DELETE /geocoder
|
987
|
+
#
|
988
|
+
# === Options
|
989
|
+
# Takes same options as +resources+.
|
919
990
|
def resource(*resources, &block)
|
920
991
|
options = resources.extract_options!
|
921
992
|
|
@@ -977,7 +1048,9 @@ module ActionDispatch
|
|
977
1048
|
# PUT /photos/:id/comments/:id
|
978
1049
|
# DELETE /photos/:id/comments/:id
|
979
1050
|
#
|
980
|
-
# ===
|
1051
|
+
# === Options
|
1052
|
+
# Takes same options as <tt>Base#match</tt> as well as:
|
1053
|
+
#
|
981
1054
|
# [:path_names]
|
982
1055
|
# Allows you to change the paths of the seven default actions.
|
983
1056
|
# Paths not specified are not changed.
|
@@ -986,20 +1059,59 @@ module ActionDispatch
|
|
986
1059
|
#
|
987
1060
|
# The above example will now change /posts/new to /posts/brand_new
|
988
1061
|
#
|
989
|
-
# [:
|
990
|
-
#
|
1062
|
+
# [:only]
|
1063
|
+
# Only generate routes for the given actions.
|
991
1064
|
#
|
992
|
-
# resources :
|
1065
|
+
# resources :cows, :only => :show
|
1066
|
+
# resources :cows, :only => [:show, :index]
|
993
1067
|
#
|
994
|
-
#
|
1068
|
+
# [:except]
|
1069
|
+
# Generate all routes except for the given actions.
|
995
1070
|
#
|
996
|
-
#
|
1071
|
+
# resources :cows, :except => :show
|
1072
|
+
# resources :cows, :except => [:show, :index]
|
1073
|
+
#
|
1074
|
+
# [:shallow]
|
1075
|
+
# Generates shallow routes for nested resource(s). When placed on a parent resource,
|
1076
|
+
# generates shallow routes for all nested resources.
|
997
1077
|
#
|
998
|
-
#
|
1078
|
+
# resources :posts, :shallow => true do
|
1079
|
+
# resources :comments
|
1080
|
+
# end
|
999
1081
|
#
|
1000
|
-
#
|
1082
|
+
# Is the same as:
|
1001
1083
|
#
|
1002
|
-
#
|
1084
|
+
# resources :posts do
|
1085
|
+
# resources :comments
|
1086
|
+
# end
|
1087
|
+
# resources :comments
|
1088
|
+
#
|
1089
|
+
# [:shallow_path]
|
1090
|
+
# Prefixes nested shallow routes with the specified path.
|
1091
|
+
#
|
1092
|
+
# scope :shallow_path => "sekret" do
|
1093
|
+
# resources :posts do
|
1094
|
+
# resources :comments, :shallow => true
|
1095
|
+
# end
|
1096
|
+
# end
|
1097
|
+
#
|
1098
|
+
# The +comments+ resource here will have the following routes generated for it:
|
1099
|
+
#
|
1100
|
+
# post_comments GET /sekret/posts/:post_id/comments(.:format)
|
1101
|
+
# post_comments POST /sekret/posts/:post_id/comments(.:format)
|
1102
|
+
# new_post_comment GET /sekret/posts/:post_id/comments/new(.:format)
|
1103
|
+
# edit_comment GET /sekret/comments/:id/edit(.:format)
|
1104
|
+
# comment GET /sekret/comments/:id(.:format)
|
1105
|
+
# comment PUT /sekret/comments/:id(.:format)
|
1106
|
+
# comment DELETE /sekret/comments/:id(.:format)
|
1107
|
+
#
|
1108
|
+
# === Examples
|
1109
|
+
#
|
1110
|
+
# # routes call Admin::PostsController
|
1111
|
+
# resources :posts, :module => "admin"
|
1112
|
+
#
|
1113
|
+
# # resource actions are at /admin/posts.
|
1114
|
+
# resources :posts, :path => "admin"
|
1003
1115
|
def resources(*resources, &block)
|
1004
1116
|
options = resources.extract_options!
|
1005
1117
|
|
@@ -1121,7 +1233,7 @@ module ActionDispatch
|
|
1121
1233
|
end
|
1122
1234
|
|
1123
1235
|
def shallow
|
1124
|
-
scope(:shallow => true) do
|
1236
|
+
scope(:shallow => true, :shallow_path => @scope[:path]) do
|
1125
1237
|
yield
|
1126
1238
|
end
|
1127
1239
|
end
|
@@ -1191,7 +1303,7 @@ module ActionDispatch
|
|
1191
1303
|
@scope[:scope_level_resource]
|
1192
1304
|
end
|
1193
1305
|
|
1194
|
-
def apply_common_behavior_for(method, resources, options, &block)
|
1306
|
+
def apply_common_behavior_for(method, resources, options, &block) #:nodoc:
|
1195
1307
|
if resources.length > 1
|
1196
1308
|
resources.each { |r| send(method, r, options, &block) }
|
1197
1309
|
return true
|
@@ -1221,24 +1333,24 @@ module ActionDispatch
|
|
1221
1333
|
false
|
1222
1334
|
end
|
1223
1335
|
|
1224
|
-
def action_options?(options)
|
1336
|
+
def action_options?(options) #:nodoc:
|
1225
1337
|
options[:only] || options[:except]
|
1226
1338
|
end
|
1227
1339
|
|
1228
|
-
def scope_action_options?
|
1340
|
+
def scope_action_options? #:nodoc:
|
1229
1341
|
@scope[:options].is_a?(Hash) && (@scope[:options][:only] || @scope[:options][:except])
|
1230
1342
|
end
|
1231
1343
|
|
1232
|
-
def scope_action_options
|
1344
|
+
def scope_action_options #:nodoc:
|
1233
1345
|
@scope[:options].slice(:only, :except)
|
1234
1346
|
end
|
1235
1347
|
|
1236
|
-
def resource_scope?
|
1237
|
-
[:
|
1348
|
+
def resource_scope? #:nodoc:
|
1349
|
+
@scope[:scope_level].in?([:resource, :resources])
|
1238
1350
|
end
|
1239
1351
|
|
1240
|
-
def resource_method_scope?
|
1241
|
-
[:collection, :member, :new]
|
1352
|
+
def resource_method_scope? #:nodoc:
|
1353
|
+
@scope[:scope_level].in?([:collection, :member, :new])
|
1242
1354
|
end
|
1243
1355
|
|
1244
1356
|
def with_exclusive_scope
|
@@ -1263,7 +1375,7 @@ module ActionDispatch
|
|
1263
1375
|
@scope[:scope_level_resource] = old_resource
|
1264
1376
|
end
|
1265
1377
|
|
1266
|
-
def resource_scope(resource)
|
1378
|
+
def resource_scope(resource) #:nodoc:
|
1267
1379
|
with_scope_level(resource.is_a?(SingletonResource) ? :resource : :resources, resource) do
|
1268
1380
|
scope(parent_resource.resource_scope) do
|
1269
1381
|
yield
|
@@ -1271,30 +1383,30 @@ module ActionDispatch
|
|
1271
1383
|
end
|
1272
1384
|
end
|
1273
1385
|
|
1274
|
-
def nested_options
|
1386
|
+
def nested_options #:nodoc:
|
1275
1387
|
{}.tap do |options|
|
1276
1388
|
options[:as] = parent_resource.member_name
|
1277
1389
|
options[:constraints] = { "#{parent_resource.singular}_id".to_sym => id_constraint } if id_constraint?
|
1278
1390
|
end
|
1279
1391
|
end
|
1280
1392
|
|
1281
|
-
def id_constraint?
|
1393
|
+
def id_constraint? #:nodoc:
|
1282
1394
|
@scope[:constraints] && @scope[:constraints][:id].is_a?(Regexp)
|
1283
1395
|
end
|
1284
1396
|
|
1285
|
-
def id_constraint
|
1397
|
+
def id_constraint #:nodoc:
|
1286
1398
|
@scope[:constraints][:id]
|
1287
1399
|
end
|
1288
1400
|
|
1289
|
-
def canonical_action?(action, flag)
|
1401
|
+
def canonical_action?(action, flag) #:nodoc:
|
1290
1402
|
flag && resource_method_scope? && CANONICAL_ACTIONS.include?(action.to_s)
|
1291
1403
|
end
|
1292
1404
|
|
1293
|
-
def shallow_scoping?
|
1405
|
+
def shallow_scoping? #:nodoc:
|
1294
1406
|
shallow? && @scope[:scope_level] == :member
|
1295
1407
|
end
|
1296
1408
|
|
1297
|
-
def path_for_action(action, path)
|
1409
|
+
def path_for_action(action, path) #:nodoc:
|
1298
1410
|
prefix = shallow_scoping? ?
|
1299
1411
|
"#{@scope[:shallow_path]}/#{parent_resource.path}/:id" : @scope[:path]
|
1300
1412
|
|
@@ -1305,11 +1417,11 @@ module ActionDispatch
|
|
1305
1417
|
end
|
1306
1418
|
end
|
1307
1419
|
|
1308
|
-
def action_path(name, path = nil)
|
1420
|
+
def action_path(name, path = nil) #:nodoc:
|
1309
1421
|
path || @scope[:path_names][name.to_sym] || name.to_s
|
1310
1422
|
end
|
1311
1423
|
|
1312
|
-
def prefix_name_for_action(as, action)
|
1424
|
+
def prefix_name_for_action(as, action) #:nodoc:
|
1313
1425
|
if as
|
1314
1426
|
as.to_s
|
1315
1427
|
elsif !canonical_action?(action, @scope[:scope_level])
|
@@ -1317,7 +1429,7 @@ module ActionDispatch
|
|
1317
1429
|
end
|
1318
1430
|
end
|
1319
1431
|
|
1320
|
-
def name_for_action(as, action)
|
1432
|
+
def name_for_action(as, action) #:nodoc:
|
1321
1433
|
prefix = prefix_name_for_action(as, action)
|
1322
1434
|
prefix = Mapper.normalize_name(prefix) if prefix
|
1323
1435
|
name_prefix = @scope[:as]
|
@@ -1349,7 +1461,7 @@ module ActionDispatch
|
|
1349
1461
|
end
|
1350
1462
|
end
|
1351
1463
|
|
1352
|
-
module Shorthand
|
1464
|
+
module Shorthand #:nodoc:
|
1353
1465
|
def match(*args)
|
1354
1466
|
if args.size == 1 && args.last.is_a?(Hash)
|
1355
1467
|
options = args.pop
|
@@ -1362,8 +1474,14 @@ module ActionDispatch
|
|
1362
1474
|
end
|
1363
1475
|
end
|
1364
1476
|
|
1477
|
+
def initialize(set) #:nodoc:
|
1478
|
+
@set = set
|
1479
|
+
@scope = { :path_names => @set.resources_path_names }
|
1480
|
+
end
|
1481
|
+
|
1365
1482
|
include Base
|
1366
1483
|
include HttpHelpers
|
1484
|
+
include Redirection
|
1367
1485
|
include Scoping
|
1368
1486
|
include Resources
|
1369
1487
|
include Shorthand
|