actionpack 3.0.0.rc → 3.0.0.rc2
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 +11 -2
- data/README.rdoc +3 -3
- data/lib/abstract_controller/base.rb +13 -1
- data/lib/action_controller.rb +2 -1
- data/lib/action_controller/base.rb +1 -1
- data/lib/action_controller/deprecated/base.rb +11 -1
- data/lib/action_controller/deprecated/url_writer.rb +14 -0
- data/lib/action_controller/metal/http_authentication.rb +3 -3
- data/lib/action_controller/metal/responder.rb +2 -8
- data/lib/action_controller/middleware.rb +1 -1
- data/lib/action_controller/test_case.rb +1 -1
- data/lib/action_controller/vendor/html-scanner/html/document.rb +2 -2
- data/lib/action_controller/vendor/html-scanner/html/node.rb +29 -29
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +25 -25
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +1 -1
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +8 -8
- data/lib/action_dispatch.rb +1 -0
- data/lib/action_dispatch/http/cache.rb +2 -2
- data/lib/action_dispatch/http/mime_type.rb +10 -10
- data/lib/action_dispatch/http/parameters.rb +2 -2
- data/lib/action_dispatch/http/request.rb +7 -0
- data/lib/action_dispatch/http/url.rb +10 -0
- data/lib/action_dispatch/middleware/best_standards_support.rb +22 -0
- data/lib/action_dispatch/middleware/cookies.rb +18 -8
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -5
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +1 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +2 -9
- data/lib/action_dispatch/middleware/stack.rb +1 -1
- data/lib/action_dispatch/railtie.rb +2 -1
- data/lib/action_dispatch/routing.rb +4 -4
- data/lib/action_dispatch/routing/deprecated_mapper.rb +1 -0
- data/lib/action_dispatch/routing/mapper.rb +34 -21
- data/lib/action_dispatch/routing/route_set.rb +8 -5
- data/lib/action_dispatch/routing/url_for.rb +1 -1
- data/lib/action_dispatch/testing/assertions/routing.rb +37 -14
- data/lib/action_dispatch/testing/integration.rb +1 -0
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_view/base.rb +1 -0
- data/lib/action_view/helpers/asset_tag_helper.rb +12 -0
- data/lib/action_view/helpers/debug_helper.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +7 -6
- data/lib/action_view/helpers/form_options_helper.rb +21 -18
- data/lib/action_view/helpers/form_tag_helper.rb +9 -9
- data/lib/action_view/helpers/number_helper.rb +1 -1
- data/lib/action_view/helpers/raw_output_helper.rb +1 -1
- data/lib/action_view/helpers/sanitize_helper.rb +4 -2
- data/lib/action_view/helpers/text_helper.rb +5 -2
- data/lib/action_view/helpers/translation_helper.rb +9 -9
- data/lib/action_view/log_subscriber.rb +1 -1
- data/lib/action_view/render/layouts.rb +8 -4
- data/lib/action_view/render/partials.rb +1 -1
- data/lib/action_view/template/handler.rb +1 -1
- data/lib/action_view/template/handlers.rb +1 -1
- data/lib/action_view/template/resolver.rb +15 -0
- data/lib/action_view/test_case.rb +1 -1
- data/lib/action_view/testing/resolvers.rb +1 -1
- metadata +18 -16
@@ -182,7 +182,7 @@ module HTML
|
|
182
182
|
# not another using <tt>:not</tt>. For example:
|
183
183
|
# p:not(.post)
|
184
184
|
# Matches all paragraphs that do not have the class <tt>.post</tt>.
|
185
|
-
#
|
185
|
+
#
|
186
186
|
# === Substitution Values
|
187
187
|
#
|
188
188
|
# You can use substitution with identifiers, class names and element values.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'strscan'
|
2
2
|
|
3
3
|
module HTML #:nodoc:
|
4
|
-
|
4
|
+
|
5
5
|
# A simple HTML tokenizer. It simply breaks a stream of text into tokens, where each
|
6
6
|
# token is a string. Each string represents either "text", or an HTML element.
|
7
7
|
#
|
@@ -14,13 +14,13 @@ module HTML #:nodoc:
|
|
14
14
|
# p token
|
15
15
|
# end
|
16
16
|
class Tokenizer #:nodoc:
|
17
|
-
|
17
|
+
|
18
18
|
# The current (byte) position in the text
|
19
19
|
attr_reader :position
|
20
|
-
|
20
|
+
|
21
21
|
# The current line number
|
22
22
|
attr_reader :line
|
23
|
-
|
23
|
+
|
24
24
|
# Create a new Tokenizer for the given text.
|
25
25
|
def initialize(text)
|
26
26
|
text.encode! if text.encoding_aware?
|
@@ -42,7 +42,7 @@ module HTML #:nodoc:
|
|
42
42
|
update_current_line(scan_text)
|
43
43
|
end
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
private
|
47
47
|
|
48
48
|
# Treat the text at the current position as a tag, and scan it. Supports
|
@@ -69,13 +69,13 @@ module HTML #:nodoc:
|
|
69
69
|
def scan_text
|
70
70
|
"#{@scanner.getch}#{@scanner.scan(/[^<]*/)}"
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
# Counts the number of newlines in the text and updates the current line
|
74
74
|
# accordingly.
|
75
75
|
def update_current_line(text)
|
76
76
|
text.scan(/\r?\n/) { @current_line += 1 }
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
# Skips over quoted strings, so that less-than and greater-than characters
|
80
80
|
# within the strings are ignored.
|
81
81
|
def consume_quoted_regions
|
@@ -103,5 +103,5 @@ module HTML #:nodoc:
|
|
103
103
|
text
|
104
104
|
end
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
end
|
data/lib/action_dispatch.rb
CHANGED
@@ -113,10 +113,10 @@ module ActionDispatch
|
|
113
113
|
DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
|
114
114
|
|
115
115
|
def set_conditional_cache_control!
|
116
|
-
control = @cache_control
|
117
|
-
|
118
116
|
return if self["Cache-Control"].present?
|
119
117
|
|
118
|
+
control = @cache_control
|
119
|
+
|
120
120
|
if control.empty?
|
121
121
|
headers["Cache-Control"] = DEFAULT_CACHE_CONTROL
|
122
122
|
elsif @cache_control[:no_cache]
|
@@ -109,10 +109,10 @@ module Mime
|
|
109
109
|
else
|
110
110
|
# keep track of creation order to keep the subsequent sort stable
|
111
111
|
list = []
|
112
|
-
accept_header.split(/,/).each_with_index do |header, index|
|
113
|
-
params, q = header.split(/;\s*q=/)
|
112
|
+
accept_header.split(/,/).each_with_index do |header, index|
|
113
|
+
params, q = header.split(/;\s*q=/)
|
114
114
|
if params
|
115
|
-
params.strip!
|
115
|
+
params.strip!
|
116
116
|
list << AcceptItem.new(index, params, q) unless params.empty?
|
117
117
|
end
|
118
118
|
end
|
@@ -161,20 +161,20 @@ module Mime
|
|
161
161
|
end
|
162
162
|
end
|
163
163
|
end
|
164
|
-
|
164
|
+
|
165
165
|
def initialize(string, symbol = nil, synonyms = [])
|
166
166
|
@symbol, @synonyms = symbol, synonyms
|
167
167
|
@string = string
|
168
168
|
end
|
169
|
-
|
169
|
+
|
170
170
|
def to_s
|
171
171
|
@string
|
172
172
|
end
|
173
|
-
|
173
|
+
|
174
174
|
def to_str
|
175
175
|
to_s
|
176
176
|
end
|
177
|
-
|
177
|
+
|
178
178
|
def to_sym
|
179
179
|
@symbol || @string.to_sym
|
180
180
|
end
|
@@ -186,11 +186,11 @@ module Mime
|
|
186
186
|
super
|
187
187
|
end
|
188
188
|
end
|
189
|
-
|
189
|
+
|
190
190
|
def ==(mime_type)
|
191
191
|
return false if mime_type.blank?
|
192
|
-
(@synonyms + [ self ]).any? do |synonym|
|
193
|
-
synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
|
192
|
+
(@synonyms + [ self ]).any? do |synonym|
|
193
|
+
synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
|
194
194
|
end
|
195
195
|
end
|
196
196
|
|
@@ -15,14 +15,14 @@ module ActionDispatch
|
|
15
15
|
alias :params :parameters
|
16
16
|
|
17
17
|
def path_parameters=(parameters) #:nodoc:
|
18
|
-
@
|
18
|
+
@_symbolized_path_params = nil
|
19
19
|
@env.delete("action_dispatch.request.parameters")
|
20
20
|
@env["action_dispatch.request.path_parameters"] = parameters
|
21
21
|
end
|
22
22
|
|
23
23
|
# The same as <tt>path_parameters</tt> with explicitly symbolized keys.
|
24
24
|
def symbolized_path_parameters
|
25
|
-
@
|
25
|
+
@_symbolized_path_params ||= path_parameters.symbolize_keys
|
26
26
|
end
|
27
27
|
|
28
28
|
# Returns a hash with the \parameters used to form the \path of the request.
|
@@ -15,6 +15,8 @@ module ActionDispatch
|
|
15
15
|
include ActionDispatch::Http::Upload
|
16
16
|
include ActionDispatch::Http::URL
|
17
17
|
|
18
|
+
LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze
|
19
|
+
|
18
20
|
%w[ AUTH_TYPE GATEWAY_INTERFACE
|
19
21
|
PATH_TRANSLATED REMOTE_HOST
|
20
22
|
REMOTE_IDENT REMOTE_USER REMOTE_ADDR
|
@@ -231,5 +233,10 @@ module ActionDispatch
|
|
231
233
|
@env['X_HTTP_AUTHORIZATION'] ||
|
232
234
|
@env['REDIRECT_X_HTTP_AUTHORIZATION']
|
233
235
|
end
|
236
|
+
|
237
|
+
# True if the request came from localhost, 127.0.0.1.
|
238
|
+
def local?
|
239
|
+
LOCALHOST.any? { |local_ip| local_ip === remote_addr && local_ip === remote_ip }
|
240
|
+
end
|
234
241
|
end
|
235
242
|
end
|
@@ -6,6 +6,11 @@ module ActionDispatch
|
|
6
6
|
protocol + host_with_port + fullpath
|
7
7
|
end
|
8
8
|
|
9
|
+
# Returns 'https' if this is an SSL request and 'http' otherwise.
|
10
|
+
def scheme
|
11
|
+
ssl? ? 'https' : 'http'
|
12
|
+
end
|
13
|
+
|
9
14
|
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
|
10
15
|
def protocol
|
11
16
|
ssl? ? 'https://' : 'http://'
|
@@ -53,6 +58,11 @@ module ActionDispatch
|
|
53
58
|
end
|
54
59
|
end
|
55
60
|
|
61
|
+
# Returns whether this request is using the standard port
|
62
|
+
def standard_port?
|
63
|
+
port == standard_port
|
64
|
+
end
|
65
|
+
|
56
66
|
# Returns a \port suffix like ":8080" if the \port number of this request
|
57
67
|
# is not the default HTTP \port 80 or HTTPS \port 443.
|
58
68
|
def port_string
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ActionDispatch
|
2
|
+
class BestStandardsSupport
|
3
|
+
def initialize(app, type = true)
|
4
|
+
@app = app
|
5
|
+
|
6
|
+
@header = case type
|
7
|
+
when true
|
8
|
+
"IE=Edge,chrome=1"
|
9
|
+
when :builtin
|
10
|
+
"IE=Edge"
|
11
|
+
when false
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
status, headers, body = @app.call(env)
|
18
|
+
headers["X-UA-Compatible"] = @header
|
19
|
+
[status, headers, body]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -69,16 +69,26 @@ module ActionDispatch
|
|
69
69
|
|
70
70
|
class CookieJar < Hash #:nodoc:
|
71
71
|
|
72
|
-
# This regular expression is used to split the levels of a domain
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
|
72
|
+
# This regular expression is used to split the levels of a domain.
|
73
|
+
# The top level domain can be any string without a period or
|
74
|
+
# **.**, ***.** style TLDs like co.uk or com.au
|
75
|
+
#
|
76
|
+
# www.example.co.uk gives:
|
77
|
+
# $1 => example
|
78
|
+
# $2 => co.uk
|
79
|
+
#
|
80
|
+
# example.com gives:
|
81
|
+
# $1 => example
|
82
|
+
# $2 => com
|
83
|
+
#
|
84
|
+
# lots.of.subdomains.example.local gives:
|
85
|
+
# $1 => example
|
86
|
+
# $2 => local
|
87
|
+
DOMAIN_REGEXP = /([^.]*)\.([^.]*|..\...|...\...)$/
|
78
88
|
|
79
89
|
def self.build(request)
|
80
90
|
secret = request.env[TOKEN_KEY]
|
81
|
-
host = request.
|
91
|
+
host = request.host
|
82
92
|
|
83
93
|
new(secret, host).tap do |hash|
|
84
94
|
hash.update(request.cookies)
|
@@ -104,7 +114,7 @@ module ActionDispatch
|
|
104
114
|
|
105
115
|
if options[:domain] == :all
|
106
116
|
@host =~ DOMAIN_REGEXP
|
107
|
-
options[:domain] = ".#{$
|
117
|
+
options[:domain] = ".#{$1}.#{$2}"
|
108
118
|
end
|
109
119
|
end
|
110
120
|
|
@@ -191,11 +191,8 @@ module ActionDispatch
|
|
191
191
|
|
192
192
|
def load_session(env)
|
193
193
|
stale_session_check! do
|
194
|
-
|
195
|
-
|
196
|
-
else
|
197
|
-
sid, session = generate_sid, {}
|
198
|
-
end
|
194
|
+
sid = current_session_id(env)
|
195
|
+
sid, session = get_session(env, sid)
|
199
196
|
[sid, session]
|
200
197
|
end
|
201
198
|
end
|
@@ -6,8 +6,6 @@ module ActionDispatch
|
|
6
6
|
# This middleware rescues any exception returned by the application and renders
|
7
7
|
# nice exception pages if it's being rescued locally.
|
8
8
|
class ShowExceptions
|
9
|
-
LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze
|
10
|
-
|
11
9
|
RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
|
12
10
|
|
13
11
|
cattr_accessor :rescue_responses
|
@@ -66,7 +64,7 @@ module ActionDispatch
|
|
66
64
|
log_error(exception)
|
67
65
|
|
68
66
|
request = Request.new(env)
|
69
|
-
if @consider_all_requests_local ||
|
67
|
+
if @consider_all_requests_local || request.local?
|
70
68
|
rescue_action_locally(request, exception)
|
71
69
|
else
|
72
70
|
rescue_action_in_public(exception)
|
@@ -112,11 +110,6 @@ module ActionDispatch
|
|
112
110
|
end
|
113
111
|
end
|
114
112
|
|
115
|
-
# True if the request came from localhost, 127.0.0.1.
|
116
|
-
def local_request?(request)
|
117
|
-
LOCALHOST.any? { |local_ip| local_ip === request.remote_addr && local_ip === request.remote_ip }
|
118
|
-
end
|
119
|
-
|
120
113
|
def status_code(exception)
|
121
114
|
Rack::Utils.status_code(@@rescue_responses[exception.class.name])
|
122
115
|
end
|
@@ -134,7 +127,7 @@ module ActionDispatch
|
|
134
127
|
|
135
128
|
ActiveSupport::Deprecation.silence do
|
136
129
|
message = "\n#{exception.class} (#{exception.message}):\n"
|
137
|
-
message << exception.annoted_source_code if exception.respond_to?(:annoted_source_code)
|
130
|
+
message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
|
138
131
|
message << " " << application_trace(exception).join("\n ")
|
139
132
|
logger.fatal("#{message}\n\n")
|
140
133
|
end
|
@@ -69,7 +69,7 @@ module ActionDispatch
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def active
|
72
|
-
ActiveSupport::Deprecation.warn "All middlewares in the chain are active since the laziness " <<
|
72
|
+
ActiveSupport::Deprecation.warn "All middlewares in the chain are active since the laziness " <<
|
73
73
|
"was removed from the middleware stack", caller
|
74
74
|
end
|
75
75
|
|
@@ -7,10 +7,11 @@ module ActionDispatch
|
|
7
7
|
config.action_dispatch.x_sendfile_header = ""
|
8
8
|
config.action_dispatch.ip_spoofing_check = true
|
9
9
|
config.action_dispatch.show_exceptions = true
|
10
|
+
config.action_dispatch.best_standards_support = true
|
10
11
|
|
11
12
|
# Prepare dispatcher callbacks and run 'prepare' callbacks
|
12
13
|
initializer "action_dispatch.prepare_dispatcher" do |app|
|
13
14
|
ActionDispatch::Callbacks.to_prepare { app.routes_reloader.execute_if_updated }
|
14
15
|
end
|
15
16
|
end
|
16
|
-
end
|
17
|
+
end
|
@@ -15,7 +15,7 @@ module ActionDispatch
|
|
15
15
|
# match ':controller(/:action(/:id(.:format)))'
|
16
16
|
#
|
17
17
|
# This route states that it expects requests to consist of a
|
18
|
-
# <tt>:controller</tt> followed optionally by an <tt>:action</tt> that in
|
18
|
+
# <tt>:controller</tt> followed optionally by an <tt>:action</tt> that in
|
19
19
|
# turn is followed optionally by an <tt>:id</tt>, which in turn is followed
|
20
20
|
# optionally by a <tt>:format</tt>
|
21
21
|
#
|
@@ -134,8 +134,8 @@ module ActionDispatch
|
|
134
134
|
# == HTTP Methods
|
135
135
|
#
|
136
136
|
# Using the <tt>:via</tt> option when specifying a route allows you to restrict it to a specific HTTP method.
|
137
|
-
# Possible values are <tt>:post</tt>, <tt>:get</tt>, <tt>:put</tt>, <tt>:delete</tt> and <tt>:any</tt>.
|
138
|
-
# If your route needs to respond to more than one method you can use an array, e.g. <tt>[ :get, :post ]</tt>.
|
137
|
+
# Possible values are <tt>:post</tt>, <tt>:get</tt>, <tt>:put</tt>, <tt>:delete</tt> and <tt>:any</tt>.
|
138
|
+
# If your route needs to respond to more than one method you can use an array, e.g. <tt>[ :get, :post ]</tt>.
|
139
139
|
# The default value is <tt>:any</tt> which means that the route will respond to any of the HTTP methods.
|
140
140
|
#
|
141
141
|
# Examples:
|
@@ -144,7 +144,7 @@ module ActionDispatch
|
|
144
144
|
# match 'post/:id' => "posts#create_comment', :via => :post
|
145
145
|
#
|
146
146
|
# Now, if you POST to <tt>/posts/:id</tt>, it will route to the <tt>create_comment</tt> action. A GET on the same
|
147
|
-
# URL will route to the <tt>show</tt> action.
|
147
|
+
# URL will route to the <tt>show</tt> action.
|
148
148
|
#
|
149
149
|
# === HTTP helper methods
|
150
150
|
#
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'erb'
|
1
2
|
require 'active_support/core_ext/hash/except'
|
2
3
|
require 'active_support/core_ext/object/blank'
|
3
4
|
|
@@ -25,13 +26,18 @@ module ActionDispatch
|
|
25
26
|
@constraints.each { |constraint|
|
26
27
|
if constraint.respond_to?(:matches?) && !constraint.matches?(req)
|
27
28
|
return [ 404, {'X-Cascade' => 'pass'}, [] ]
|
28
|
-
elsif constraint.respond_to?(:call) && !constraint.call(req)
|
29
|
+
elsif constraint.respond_to?(:call) && !constraint.call(*constraint_args(constraint, req))
|
29
30
|
return [ 404, {'X-Cascade' => 'pass'}, [] ]
|
30
31
|
end
|
31
32
|
}
|
32
33
|
|
33
34
|
@app.call(env)
|
34
35
|
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def constraint_args(constraint, request)
|
39
|
+
constraint.arity == 1 ? [request] : [request.symbolized_path_parameters, request]
|
40
|
+
end
|
35
41
|
end
|
36
42
|
|
37
43
|
class Mapping #:nodoc:
|
@@ -277,7 +283,6 @@ module ActionDispatch
|
|
277
283
|
path = args.shift || block
|
278
284
|
path_proc = path.is_a?(Proc) ? path : proc { |params| path % params }
|
279
285
|
status = options[:status] || 301
|
280
|
-
body = 'Moved Permanently'
|
281
286
|
|
282
287
|
lambda do |env|
|
283
288
|
req = Request.new(env)
|
@@ -288,13 +293,16 @@ module ActionDispatch
|
|
288
293
|
uri = URI.parse(path_proc.call(*params))
|
289
294
|
uri.scheme ||= req.scheme
|
290
295
|
uri.host ||= req.host
|
291
|
-
uri.port ||= req.port unless req.
|
296
|
+
uri.port ||= req.port unless req.standard_port?
|
297
|
+
|
298
|
+
body = %(<html><body>You are being <a href="#{ERB::Util.h(uri.to_s)}">redirected</a>.</body></html>)
|
292
299
|
|
293
300
|
headers = {
|
294
301
|
'Location' => uri.to_s,
|
295
302
|
'Content-Type' => 'text/html',
|
296
303
|
'Content-Length' => body.length.to_s
|
297
304
|
}
|
305
|
+
|
298
306
|
[ status, headers, [body] ]
|
299
307
|
end
|
300
308
|
end
|
@@ -470,7 +478,7 @@ module ActionDispatch
|
|
470
478
|
|
471
479
|
def initialize(entities, options = {})
|
472
480
|
@name = entities.to_s
|
473
|
-
@path = options.delete(:path) || @name
|
481
|
+
@path = (options.delete(:path) || @name).to_s
|
474
482
|
@controller = (options.delete(:controller) || @name).to_s
|
475
483
|
@as = options.delete(:as)
|
476
484
|
@options = options
|
@@ -495,16 +503,14 @@ module ActionDispatch
|
|
495
503
|
end
|
496
504
|
|
497
505
|
def plural
|
498
|
-
name.to_s
|
506
|
+
@plural ||= name.to_s
|
499
507
|
end
|
500
508
|
|
501
509
|
def singular
|
502
|
-
name.to_s.singularize
|
510
|
+
@singular ||= name.to_s.singularize
|
503
511
|
end
|
504
512
|
|
505
|
-
|
506
|
-
singular
|
507
|
-
end
|
513
|
+
alias :member_name :singular
|
508
514
|
|
509
515
|
# Checks for uncountable plurals, and appends "_index" if they're.
|
510
516
|
def collection_name
|
@@ -515,9 +521,7 @@ module ActionDispatch
|
|
515
521
|
{ :controller => controller }
|
516
522
|
end
|
517
523
|
|
518
|
-
|
519
|
-
path
|
520
|
-
end
|
524
|
+
alias :collection_scope :path
|
521
525
|
|
522
526
|
def member_scope
|
523
527
|
"#{path}/:id"
|
@@ -538,21 +542,25 @@ module ActionDispatch
|
|
538
542
|
|
539
543
|
def initialize(entities, options)
|
540
544
|
@name = entities.to_s
|
541
|
-
@path = options.delete(:path) || @name
|
545
|
+
@path = (options.delete(:path) || @name).to_s
|
542
546
|
@controller = (options.delete(:controller) || plural).to_s
|
543
547
|
@as = options.delete(:as)
|
544
548
|
@options = options
|
545
549
|
end
|
546
550
|
|
547
|
-
def
|
548
|
-
name
|
551
|
+
def plural
|
552
|
+
@plural ||= name.to_s.pluralize
|
549
553
|
end
|
550
|
-
alias :collection_name :member_name
|
551
554
|
|
552
|
-
def
|
553
|
-
|
555
|
+
def singular
|
556
|
+
@singular ||= name.to_s
|
554
557
|
end
|
555
|
-
|
558
|
+
|
559
|
+
alias :member_name :singular
|
560
|
+
alias :collection_name :singular
|
561
|
+
|
562
|
+
alias :member_scope :path
|
563
|
+
alias :nested_scope :path
|
556
564
|
end
|
557
565
|
|
558
566
|
def initialize(*args) #:nodoc:
|
@@ -583,10 +591,10 @@ module ActionDispatch
|
|
583
591
|
end if parent_resource.actions.include?(:new)
|
584
592
|
|
585
593
|
member_scope do
|
594
|
+
get :edit if parent_resource.actions.include?(:edit)
|
586
595
|
get :show if parent_resource.actions.include?(:show)
|
587
596
|
put :update if parent_resource.actions.include?(:update)
|
588
597
|
delete :destroy if parent_resource.actions.include?(:destroy)
|
589
|
-
get :edit if parent_resource.actions.include?(:edit)
|
590
598
|
end
|
591
599
|
end
|
592
600
|
|
@@ -613,10 +621,10 @@ module ActionDispatch
|
|
613
621
|
end if parent_resource.actions.include?(:new)
|
614
622
|
|
615
623
|
member_scope do
|
624
|
+
get :edit if parent_resource.actions.include?(:edit)
|
616
625
|
get :show if parent_resource.actions.include?(:show)
|
617
626
|
put :update if parent_resource.actions.include?(:update)
|
618
627
|
delete :destroy if parent_resource.actions.include?(:destroy)
|
619
|
-
get :edit if parent_resource.actions.include?(:edit)
|
620
628
|
end
|
621
629
|
end
|
622
630
|
|
@@ -728,6 +736,7 @@ module ActionDispatch
|
|
728
736
|
end
|
729
737
|
elsif resource_method_scope?
|
730
738
|
path = path_for_custom_action
|
739
|
+
options[:action] ||= action
|
731
740
|
options[:as] = name_for_action(options[:as]) if options[:as]
|
732
741
|
args.push(options)
|
733
742
|
|
@@ -770,6 +779,10 @@ module ActionDispatch
|
|
770
779
|
return true
|
771
780
|
end
|
772
781
|
|
782
|
+
options.keys.each do |k|
|
783
|
+
(options[:constraints] ||= {})[k] = options.delete(k) if options[k].is_a?(Regexp)
|
784
|
+
end
|
785
|
+
|
773
786
|
scope_options = options.slice!(*RESOURCE_OPTIONS)
|
774
787
|
unless scope_options.empty?
|
775
788
|
scope(scope_options) do
|