actionpack 3.1.12 → 3.2.0.rc1
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.md +5503 -108
- data/README.rdoc +3 -3
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +102 -18
- data/lib/abstract_controller/helpers.rb +1 -1
- data/lib/abstract_controller/layouts.rb +116 -50
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
- data/lib/abstract_controller/rendering.rb +1 -6
- data/lib/abstract_controller/view_paths.rb +6 -5
- data/lib/action_controller.rb +0 -15
- data/lib/action_controller/caching.rb +0 -1
- data/lib/action_controller/caching/actions.rb +5 -6
- data/lib/action_controller/caching/fragments.rb +18 -18
- data/lib/action_controller/caching/pages.rb +7 -6
- data/lib/action_controller/caching/sweeping.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +8 -4
- data/lib/action_controller/metal.rb +7 -1
- data/lib/action_controller/metal/conditional_get.rb +49 -4
- data/lib/action_controller/metal/data_streaming.rb +17 -5
- data/lib/action_controller/metal/force_ssl.rb +8 -5
- data/lib/action_controller/metal/helpers.rb +7 -4
- data/lib/action_controller/metal/http_authentication.rb +9 -12
- data/lib/action_controller/metal/instrumentation.rb +9 -4
- data/lib/action_controller/metal/mime_responds.rb +4 -4
- data/lib/action_controller/metal/params_wrapper.rb +12 -8
- data/lib/action_controller/metal/redirecting.rb +7 -6
- data/lib/action_controller/metal/renderers.rb +9 -11
- data/lib/action_controller/metal/request_forgery_protection.rb +2 -1
- data/lib/action_controller/metal/rescue.rb +13 -0
- data/lib/action_controller/metal/responder.rb +11 -23
- data/lib/action_controller/metal/streaming.rb +0 -25
- data/lib/action_controller/railtie.rb +1 -0
- data/lib/action_controller/railties/paths.rb +4 -3
- data/lib/action_controller/record_identifier.rb +4 -4
- data/lib/action_controller/test_case.rb +60 -56
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +6 -6
- data/lib/action_dispatch.rb +5 -1
- data/lib/action_dispatch/http/cache.rb +27 -15
- data/lib/action_dispatch/http/filter_parameters.rb +3 -1
- data/lib/action_dispatch/http/headers.rb +3 -5
- data/lib/action_dispatch/http/mime_negotiation.rb +2 -1
- data/lib/action_dispatch/http/mime_type.rb +7 -3
- data/lib/action_dispatch/http/mime_types.rb +12 -0
- data/lib/action_dispatch/http/parameter_filter.rb +3 -1
- data/lib/action_dispatch/http/parameters.rb +0 -4
- data/lib/action_dispatch/http/request.rb +18 -68
- data/lib/action_dispatch/http/response.rb +11 -32
- data/lib/action_dispatch/http/upload.rb +3 -14
- data/lib/action_dispatch/http/url.rb +1 -1
- data/lib/action_dispatch/middleware/callbacks.rb +1 -2
- data/lib/action_dispatch/middleware/cookies.rb +20 -16
- data/lib/action_dispatch/middleware/debug_exceptions.rb +82 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +78 -0
- data/lib/action_dispatch/middleware/flash.rb +6 -9
- data/lib/action_dispatch/middleware/params_parser.rb +6 -11
- data/lib/action_dispatch/middleware/public_exceptions.rb +30 -0
- data/lib/action_dispatch/middleware/reloader.rb +38 -14
- data/lib/action_dispatch/middleware/remote_ip.rb +66 -36
- data/lib/action_dispatch/middleware/request_id.rb +39 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +4 -16
- data/lib/action_dispatch/middleware/session/cache_store.rb +50 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +58 -142
- data/lib/action_dispatch/middleware/static.rb +2 -10
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +13 -8
- data/lib/action_dispatch/railtie.rb +15 -1
- data/lib/action_dispatch/routing.rb +1 -2
- data/lib/action_dispatch/routing/mapper.rb +108 -107
- data/lib/action_dispatch/routing/redirection.rb +63 -69
- data/lib/action_dispatch/routing/route_set.rb +75 -43
- data/lib/action_dispatch/routing/routes_proxy.rb +0 -4
- data/lib/action_dispatch/routing/url_for.rb +3 -3
- data/lib/action_dispatch/testing/assertions/response.rb +5 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +10 -9
- data/lib/action_dispatch/testing/integration.rb +8 -25
- data/lib/action_dispatch/testing/test_process.rb +3 -2
- data/lib/action_dispatch/testing/test_request.rb +4 -23
- data/lib/action_pack/version.rb +3 -3
- data/lib/action_view.rb +1 -5
- data/lib/action_view/asset_paths.rb +7 -8
- data/lib/action_view/base.rb +7 -5
- data/lib/action_view/helpers/asset_paths.rb +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +4 -8
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +3 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
- data/lib/action_view/helpers/capture_helper.rb +3 -3
- data/lib/action_view/helpers/controller_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +26 -18
- data/lib/action_view/helpers/debug_helper.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +71 -13
- data/lib/action_view/helpers/form_options_helper.rb +65 -34
- data/lib/action_view/helpers/form_tag_helper.rb +24 -18
- data/lib/action_view/helpers/javascript_helper.rb +12 -3
- data/lib/action_view/helpers/number_helper.rb +3 -2
- data/lib/action_view/helpers/record_tag_helper.rb +51 -5
- data/lib/action_view/helpers/rendering_helper.rb +2 -2
- data/lib/action_view/helpers/sanitize_helper.rb +6 -7
- data/lib/action_view/helpers/tag_helper.rb +1 -1
- data/lib/action_view/helpers/text_helper.rb +5 -4
- data/lib/action_view/helpers/url_helper.rb +19 -11
- data/lib/action_view/locale/en.yml +6 -0
- data/lib/action_view/log_subscriber.rb +1 -1
- data/lib/action_view/lookup_context.rb +123 -125
- data/lib/action_view/path_set.rb +60 -13
- data/lib/action_view/renderer/abstract_renderer.rb +16 -11
- data/lib/action_view/renderer/partial_renderer.rb +59 -40
- data/lib/action_view/renderer/template_renderer.rb +29 -17
- data/lib/action_view/template.rb +0 -1
- data/lib/action_view/template/error.rb +6 -5
- data/lib/action_view/template/handlers.rb +0 -6
- data/lib/action_view/template/handlers/builder.rb +10 -1
- data/lib/action_view/template/handlers/erb.rb +2 -2
- data/lib/action_view/template/resolver.rb +20 -31
- data/lib/action_view/test_case.rb +7 -10
- data/lib/sprockets/assets.rake +1 -1
- data/lib/sprockets/bootstrap.rb +3 -31
- data/lib/sprockets/compressors.rb +69 -7
- data/lib/sprockets/helpers/rails_helper.rb +6 -11
- data/lib/sprockets/railtie.rb +1 -0
- data/lib/sprockets/static_compiler.rb +0 -3
- metadata +57 -86
- checksums.yaml +0 -7
- data/lib/action_dispatch/middleware/closed_error.rb +0 -7
- data/lib/action_dispatch/routing/route.rb +0 -67
- data/lib/action_view/template/handler.rb +0 -49
@@ -11,14 +11,14 @@ module ActionDispatch
|
|
11
11
|
def match?(path)
|
12
12
|
path = path.dup
|
13
13
|
|
14
|
-
full_path = path.empty? ? @root : File.join(@root,
|
14
|
+
full_path = path.empty? ? @root : File.join(@root, ::Rack::Utils.unescape(path))
|
15
15
|
paths = "#{full_path}#{ext}"
|
16
16
|
|
17
17
|
matches = Dir[paths]
|
18
18
|
match = matches.detect { |m| File.file?(m) }
|
19
19
|
if match
|
20
20
|
match.sub!(@compiled_root, '')
|
21
|
-
|
21
|
+
match
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -32,14 +32,6 @@ module ActionDispatch
|
|
32
32
|
"{,#{ext},/index#{ext}}"
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
36
|
-
def unescape_path(path)
|
37
|
-
URI.parser.unescape(path)
|
38
|
-
end
|
39
|
-
|
40
|
-
def escape_glob_chars(path)
|
41
|
-
path.gsub(/[*?{}\[\]]/, "\\\\\\&")
|
42
|
-
end
|
43
35
|
end
|
44
36
|
|
45
37
|
class Static
|
@@ -1,10 +1,15 @@
|
|
1
1
|
<h1>Routing Error</h1>
|
2
2
|
<p><pre><%=h @exception.message %></pre></p>
|
3
|
-
<% unless @exception.failures.empty?
|
4
|
-
<
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
</
|
3
|
+
<% unless @exception.failures.empty? %>
|
4
|
+
<p>
|
5
|
+
<h2>Failure reasons:</h2>
|
6
|
+
<ol>
|
7
|
+
<% @exception.failures.each do |route, reason| %>
|
8
|
+
<li><code><%=h route.inspect.gsub('\\', '') %></code> failed because <%=h reason.downcase %></li>
|
9
|
+
<% end %>
|
10
|
+
</ol>
|
11
|
+
</p>
|
12
|
+
<% end %>
|
13
|
+
<p>
|
14
|
+
Try running <code>rake routes</code> for more information on available routes.
|
15
|
+
</p>
|
@@ -9,11 +9,25 @@ module ActionDispatch
|
|
9
9
|
config.action_dispatch.best_standards_support = true
|
10
10
|
config.action_dispatch.tld_length = 1
|
11
11
|
config.action_dispatch.ignore_accept_header = false
|
12
|
-
config.action_dispatch.
|
12
|
+
config.action_dispatch.rescue_templates = { }
|
13
|
+
config.action_dispatch.rescue_responses = { }
|
14
|
+
|
15
|
+
config.action_dispatch.rack_cache = {
|
16
|
+
:metastore => "rails:/",
|
17
|
+
:entitystore => "rails:/",
|
18
|
+
:verbose => true
|
19
|
+
}
|
13
20
|
|
14
21
|
initializer "action_dispatch.configure" do |app|
|
15
22
|
ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length
|
16
23
|
ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header
|
24
|
+
ActionDispatch::Response.default_charset = app.config.encoding
|
25
|
+
|
26
|
+
ActionDispatch::ExceptionWrapper.rescue_responses.merge!(config.action_dispatch.rescue_responses)
|
27
|
+
ActionDispatch::ExceptionWrapper.rescue_templates.merge!(config.action_dispatch.rescue_templates)
|
28
|
+
|
29
|
+
config.action_dispatch.always_write_cookie = Rails.env.development? if config.action_dispatch.always_write_cookie.nil?
|
30
|
+
ActionDispatch::Cookies::CookieJar.always_write_cookie = config.action_dispatch.always_write_cookie
|
17
31
|
end
|
18
32
|
end
|
19
33
|
end
|
@@ -161,7 +161,7 @@ module ActionDispatch
|
|
161
161
|
# Consider the following route, which you will find commented out at the
|
162
162
|
# bottom of your generated <tt>config/routes.rb</tt>:
|
163
163
|
#
|
164
|
-
# match ':controller(/:action(/:id(.:format)
|
164
|
+
# match ':controller(/:action(/:id))(.:format)'
|
165
165
|
#
|
166
166
|
# This route states that it expects requests to consist of a
|
167
167
|
# <tt>:controller</tt> followed optionally by an <tt>:action</tt> that in
|
@@ -277,7 +277,6 @@ module ActionDispatch
|
|
277
277
|
#
|
278
278
|
module Routing
|
279
279
|
autoload :Mapper, 'action_dispatch/routing/mapper'
|
280
|
-
autoload :Route, 'action_dispatch/routing/route'
|
281
280
|
autoload :RouteSet, 'action_dispatch/routing/route_set'
|
282
281
|
autoload :RoutesProxy, 'action_dispatch/routing/routes_proxy'
|
283
282
|
autoload :UrlFor, 'action_dispatch/routing/url_for'
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'erb'
|
2
1
|
require 'active_support/core_ext/hash/except'
|
3
2
|
require 'active_support/core_ext/object/blank'
|
4
3
|
require 'active_support/core_ext/object/inclusion'
|
@@ -35,8 +34,6 @@ module ActionDispatch
|
|
35
34
|
}
|
36
35
|
|
37
36
|
return true
|
38
|
-
ensure
|
39
|
-
req.reset_parameters
|
40
37
|
end
|
41
38
|
|
42
39
|
def call(env)
|
@@ -51,6 +48,9 @@ module ActionDispatch
|
|
51
48
|
|
52
49
|
class Mapping #:nodoc:
|
53
50
|
IGNORE_OPTIONS = [:to, :as, :via, :on, :constraints, :defaults, :only, :except, :anchor, :shallow, :shallow_path, :shallow_prefix]
|
51
|
+
ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
|
52
|
+
SHORTHAND_REGEX = %r{/[\w/]+$}
|
53
|
+
WILDCARD_PATH = %r{\*([^/\)]+)\)?$}
|
54
54
|
|
55
55
|
def initialize(set, scope, path, options)
|
56
56
|
@set, @scope = set, scope
|
@@ -70,7 +70,7 @@ module ActionDispatch
|
|
70
70
|
|
71
71
|
if using_match_shorthand?(path_without_format, @options)
|
72
72
|
to_shorthand = @options[:to].blank?
|
73
|
-
@options[:to] ||= path_without_format[1..-1].sub(%r{/([^/]*)$}, '#\1')
|
73
|
+
@options[:to] ||= path_without_format.gsub(/\(.*\)/, "")[1..-1].sub(%r{/([^/]*)$}, '#\1')
|
74
74
|
end
|
75
75
|
|
76
76
|
@options.merge!(default_controller_and_action(to_shorthand))
|
@@ -79,7 +79,7 @@ module ActionDispatch
|
|
79
79
|
# segment_keys.include?(k.to_s) || k == :controller
|
80
80
|
next unless Regexp === requirement && !constraints[name]
|
81
81
|
|
82
|
-
if requirement.source =~
|
82
|
+
if requirement.source =~ ANCHOR_CHARACTERS_REGEX
|
83
83
|
raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
|
84
84
|
end
|
85
85
|
if requirement.multiline?
|
@@ -90,7 +90,7 @@ module ActionDispatch
|
|
90
90
|
|
91
91
|
# match "account/overview"
|
92
92
|
def using_match_shorthand?(path, options)
|
93
|
-
path && options
|
93
|
+
path && (options[:to] || options[:action]).nil? && path =~ SHORTHAND_REGEX
|
94
94
|
end
|
95
95
|
|
96
96
|
def normalize_path(path)
|
@@ -104,13 +104,13 @@ module ActionDispatch
|
|
104
104
|
# controllers with default routes like :controller/:action/:id(.:format), e.g:
|
105
105
|
# GET /admin/products/show/1
|
106
106
|
# => { :controller => 'admin/products', :action => 'show', :id => '1' }
|
107
|
-
@options
|
107
|
+
@options[:controller] ||= /.+?/
|
108
108
|
end
|
109
109
|
|
110
110
|
# Add a constraint for wildcard route to make it non-greedy and match the
|
111
111
|
# optional format part of the route by default
|
112
|
-
if path.match(
|
113
|
-
@options
|
112
|
+
if path.match(WILDCARD_PATH) && @options[:format] != false
|
113
|
+
@options[$1.to_sym] ||= /.+?/
|
114
114
|
end
|
115
115
|
|
116
116
|
if @options[:format] == false
|
@@ -213,8 +213,8 @@ module ActionDispatch
|
|
213
213
|
end
|
214
214
|
|
215
215
|
def segment_keys
|
216
|
-
@segment_keys ||=
|
217
|
-
|
216
|
+
@segment_keys ||= Journey::Path::Pattern.new(
|
217
|
+
Journey::Router::Strexp.compile(@path, requirements, SEPARATORS)
|
218
218
|
).names
|
219
219
|
end
|
220
220
|
|
@@ -223,19 +223,11 @@ module ActionDispatch
|
|
223
223
|
end
|
224
224
|
|
225
225
|
def default_controller
|
226
|
-
|
227
|
-
@options[:controller]
|
228
|
-
elsif @scope[:controller]
|
229
|
-
@scope[:controller]
|
230
|
-
end
|
226
|
+
@options[:controller] || @scope[:controller]
|
231
227
|
end
|
232
228
|
|
233
229
|
def default_action
|
234
|
-
|
235
|
-
@options[:action]
|
236
|
-
elsif @scope[:action]
|
237
|
-
@scope[:action]
|
238
|
-
end
|
230
|
+
@options[:action] || @scope[:action]
|
239
231
|
end
|
240
232
|
end
|
241
233
|
|
@@ -243,7 +235,7 @@ module ActionDispatch
|
|
243
235
|
# (:locale) becomes (/:locale) instead of /(:locale). Except
|
244
236
|
# for root cases, where the latter is the correct one.
|
245
237
|
def self.normalize_path(path)
|
246
|
-
path =
|
238
|
+
path = Journey::Router::Utils.normalize_path(path)
|
247
239
|
path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/\(+[^/]+\)$}
|
248
240
|
path
|
249
241
|
end
|
@@ -263,7 +255,7 @@ module ActionDispatch
|
|
263
255
|
# because this means it will be matched first. As this is the most popular route
|
264
256
|
# of most Rails applications, this is beneficial.
|
265
257
|
def root(options = {})
|
266
|
-
match '/',
|
258
|
+
match '/', { :as => :root }.merge(options)
|
267
259
|
end
|
268
260
|
|
269
261
|
# Matches a url pattern to one or more routes. Any symbols in a pattern
|
@@ -293,7 +285,7 @@ module ActionDispatch
|
|
293
285
|
# A pattern can also point to a +Rack+ endpoint i.e. anything that
|
294
286
|
# responds to +call+:
|
295
287
|
#
|
296
|
-
# match 'photos/:id' => lambda {|hash| [200, {}, "Coming soon" }
|
288
|
+
# match 'photos/:id' => lambda {|hash| [200, {}, "Coming soon"] }
|
297
289
|
# match 'photos/:id' => PhotoRackApp
|
298
290
|
# # Yes, controller actions are just rack endpoints
|
299
291
|
# match 'photos/:id' => PhotosController.action(:show)
|
@@ -333,12 +325,12 @@ module ActionDispatch
|
|
333
325
|
# +call+ or a string representing a controller's action.
|
334
326
|
#
|
335
327
|
# match 'path', :to => 'controller#action'
|
336
|
-
# match 'path', :to => lambda {
|
328
|
+
# match 'path', :to => lambda { [200, {}, "Success!"] }
|
337
329
|
# match 'path', :to => RackApp
|
338
330
|
#
|
339
331
|
# [:on]
|
340
332
|
# Shorthand for wrapping routes in a specific RESTful context. Valid
|
341
|
-
# values are +:member+, +:collection+, and +:new+.
|
333
|
+
# values are +:member+, +:collection+, and +:new+. Only use within
|
342
334
|
# <tt>resource(s)</tt> block. For example:
|
343
335
|
#
|
344
336
|
# resource :bar do
|
@@ -382,10 +374,6 @@ module ActionDispatch
|
|
382
374
|
# # Matches any request starting with 'path'
|
383
375
|
# match 'path' => 'c#a', :anchor => false
|
384
376
|
def match(path, options=nil)
|
385
|
-
mapping = Mapping.new(@set, @scope, path, options || {})
|
386
|
-
app, conditions, requirements, defaults, as, anchor = mapping.to_route
|
387
|
-
@set.add_route(app, conditions, requirements, defaults, as, anchor)
|
388
|
-
self
|
389
377
|
end
|
390
378
|
|
391
379
|
# Mount a Rack-based application to be used within the application.
|
@@ -583,8 +571,8 @@ module ActionDispatch
|
|
583
571
|
# end
|
584
572
|
#
|
585
573
|
# This generates helpers such as +account_projects_path+, just like +resources+ does.
|
586
|
-
# The difference here being that the routes generated are like /
|
587
|
-
# rather than /accounts/
|
574
|
+
# The difference here being that the routes generated are like /:account_id/projects,
|
575
|
+
# rather than /accounts/:account_id/projects.
|
588
576
|
#
|
589
577
|
# === Options
|
590
578
|
#
|
@@ -661,13 +649,13 @@ module ActionDispatch
|
|
661
649
|
#
|
662
650
|
# This generates the following routes:
|
663
651
|
#
|
664
|
-
# admin_posts GET /admin/posts(.:format)
|
665
|
-
# admin_posts POST /admin/posts(.:format)
|
666
|
-
# new_admin_post GET /admin/posts/new(.:format)
|
667
|
-
# edit_admin_post GET /admin/posts/:id/edit(.:format)
|
668
|
-
# admin_post GET /admin/posts/:id(.:format)
|
669
|
-
# admin_post PUT /admin/posts/:id(.:format)
|
670
|
-
# admin_post DELETE /admin/posts/:id(.:format)
|
652
|
+
# admin_posts GET /admin/posts(.:format) admin/posts#index
|
653
|
+
# admin_posts POST /admin/posts(.:format) admin/posts#create
|
654
|
+
# new_admin_post GET /admin/posts/new(.:format) admin/posts#new
|
655
|
+
# edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
|
656
|
+
# admin_post GET /admin/posts/:id(.:format) admin/posts#show
|
657
|
+
# admin_post PUT /admin/posts/:id(.:format) admin/posts#update
|
658
|
+
# admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
|
671
659
|
#
|
672
660
|
# === Options
|
673
661
|
#
|
@@ -875,8 +863,6 @@ module ActionDispatch
|
|
875
863
|
CANONICAL_ACTIONS = %w(index create new show update destroy)
|
876
864
|
|
877
865
|
class Resource #:nodoc:
|
878
|
-
DEFAULT_ACTIONS = [:index, :create, :new, :show, :update, :destroy, :edit]
|
879
|
-
|
880
866
|
attr_reader :controller, :path, :options
|
881
867
|
|
882
868
|
def initialize(entities, options = {})
|
@@ -888,7 +874,7 @@ module ActionDispatch
|
|
888
874
|
end
|
889
875
|
|
890
876
|
def default_actions
|
891
|
-
|
877
|
+
[:index, :create, :new, :show, :update, :destroy, :edit]
|
892
878
|
end
|
893
879
|
|
894
880
|
def actions
|
@@ -942,16 +928,17 @@ module ActionDispatch
|
|
942
928
|
end
|
943
929
|
|
944
930
|
class SingletonResource < Resource #:nodoc:
|
945
|
-
DEFAULT_ACTIONS = [:show, :create, :update, :destroy, :new, :edit]
|
946
|
-
|
947
931
|
def initialize(entities, options)
|
948
932
|
super
|
949
|
-
|
950
933
|
@as = nil
|
951
934
|
@controller = (options[:controller] || plural).to_s
|
952
935
|
@as = options[:as]
|
953
936
|
end
|
954
937
|
|
938
|
+
def default_actions
|
939
|
+
[:show, :create, :update, :destroy, :new, :edit]
|
940
|
+
end
|
941
|
+
|
955
942
|
def plural
|
956
943
|
@plural ||= name.to_s.pluralize
|
957
944
|
end
|
@@ -999,7 +986,7 @@ module ActionDispatch
|
|
999
986
|
return self
|
1000
987
|
end
|
1001
988
|
|
1002
|
-
resource_scope(SingletonResource.new(resources.pop, options)) do
|
989
|
+
resource_scope(:resource, SingletonResource.new(resources.pop, options)) do
|
1003
990
|
yield if block_given?
|
1004
991
|
|
1005
992
|
collection do
|
@@ -1031,6 +1018,7 @@ module ActionDispatch
|
|
1031
1018
|
# creates seven different routes in your application, all mapping to
|
1032
1019
|
# the +Photos+ controller:
|
1033
1020
|
#
|
1021
|
+
# GET /photos
|
1034
1022
|
# GET /photos/new
|
1035
1023
|
# POST /photos
|
1036
1024
|
# GET /photos/:id
|
@@ -1046,19 +1034,20 @@ module ActionDispatch
|
|
1046
1034
|
#
|
1047
1035
|
# This generates the following comments routes:
|
1048
1036
|
#
|
1049
|
-
# GET /photos/:
|
1050
|
-
#
|
1051
|
-
#
|
1052
|
-
# GET /photos/:
|
1053
|
-
#
|
1054
|
-
#
|
1037
|
+
# GET /photos/:photo_id/comments
|
1038
|
+
# GET /photos/:photo_id/comments/new
|
1039
|
+
# POST /photos/:photo_id/comments
|
1040
|
+
# GET /photos/:photo_id/comments/:id
|
1041
|
+
# GET /photos/:photo_id/comments/:id/edit
|
1042
|
+
# PUT /photos/:photo_id/comments/:id
|
1043
|
+
# DELETE /photos/:photo_id/comments/:id
|
1055
1044
|
#
|
1056
1045
|
# === Options
|
1057
1046
|
# Takes same options as <tt>Base#match</tt> as well as:
|
1058
1047
|
#
|
1059
1048
|
# [:path_names]
|
1060
|
-
# Allows you to change the
|
1061
|
-
#
|
1049
|
+
# Allows you to change the segment component of the +edit+ and +new+ actions.
|
1050
|
+
# Actions not specified are not changed.
|
1062
1051
|
#
|
1063
1052
|
# resources :posts, :path_names => { :new => "brand_new" }
|
1064
1053
|
#
|
@@ -1098,11 +1087,11 @@ module ActionDispatch
|
|
1098
1087
|
# [:shallow_path]
|
1099
1088
|
# Prefixes nested shallow routes with the specified path.
|
1100
1089
|
#
|
1101
|
-
#
|
1102
|
-
#
|
1103
|
-
#
|
1090
|
+
# scope :shallow_path => "sekret" do
|
1091
|
+
# resources :posts do
|
1092
|
+
# resources :comments, :shallow => true
|
1093
|
+
# end
|
1104
1094
|
# end
|
1105
|
-
# end
|
1106
1095
|
#
|
1107
1096
|
# The +comments+ resource here will have the following routes generated for it:
|
1108
1097
|
#
|
@@ -1128,7 +1117,7 @@ module ActionDispatch
|
|
1128
1117
|
return self
|
1129
1118
|
end
|
1130
1119
|
|
1131
|
-
resource_scope(Resource.new(resources.pop, options)) do
|
1120
|
+
resource_scope(:resources, Resource.new(resources.pop, options)) do
|
1132
1121
|
yield if block_given?
|
1133
1122
|
|
1134
1123
|
collection do
|
@@ -1251,32 +1240,44 @@ module ActionDispatch
|
|
1251
1240
|
parent_resource.instance_of?(Resource) && @scope[:shallow]
|
1252
1241
|
end
|
1253
1242
|
|
1254
|
-
def match(*
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1243
|
+
def match(path, *rest)
|
1244
|
+
if rest.empty? && Hash === path
|
1245
|
+
options = path
|
1246
|
+
path, to = options.find { |name, value| name.is_a?(String) }
|
1247
|
+
options[:to] = to
|
1248
|
+
options.delete(path)
|
1249
|
+
paths = [path]
|
1250
|
+
else
|
1251
|
+
options = rest.pop || {}
|
1252
|
+
paths = [path] + rest
|
1261
1253
|
end
|
1262
1254
|
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
return send(on){ match(*args) }
|
1267
|
-
elsif on
|
1255
|
+
options[:anchor] = true unless options.key?(:anchor)
|
1256
|
+
|
1257
|
+
if options[:on] && !VALID_ON_OPTIONS.include?(options[:on])
|
1268
1258
|
raise ArgumentError, "Unknown scope #{on.inspect} given to :on"
|
1269
1259
|
end
|
1270
1260
|
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1261
|
+
paths.each { |_path| decomposed_match(_path, options.dup) }
|
1262
|
+
self
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
def decomposed_match(path, options) # :nodoc:
|
1266
|
+
if on = options.delete(:on)
|
1267
|
+
send(on) { decomposed_match(path, options) }
|
1268
|
+
else
|
1269
|
+
case @scope[:scope_level]
|
1270
|
+
when :resources
|
1271
|
+
nested { decomposed_match(path, options) }
|
1272
|
+
when :resource
|
1273
|
+
member { decomposed_match(path, options) }
|
1274
|
+
else
|
1275
|
+
add_route(path, options)
|
1276
|
+
end
|
1277
1277
|
end
|
1278
|
+
end
|
1278
1279
|
|
1279
|
-
|
1280
|
+
def add_route(action, options) # :nodoc:
|
1280
1281
|
path = path_for_action(action, options.delete(:path))
|
1281
1282
|
|
1282
1283
|
if action.to_s =~ /^[\w\/]+$/
|
@@ -1285,13 +1286,15 @@ module ActionDispatch
|
|
1285
1286
|
action = nil
|
1286
1287
|
end
|
1287
1288
|
|
1288
|
-
if options.
|
1289
|
+
if !options.fetch(:as, true)
|
1289
1290
|
options.delete(:as)
|
1290
1291
|
else
|
1291
1292
|
options[:as] = name_for_action(options[:as], action)
|
1292
1293
|
end
|
1293
1294
|
|
1294
|
-
|
1295
|
+
mapping = Mapping.new(@set, @scope, path, options)
|
1296
|
+
app, conditions, requirements, defaults, as, anchor = mapping.to_route
|
1297
|
+
@set.add_route(app, conditions, requirements, defaults, as, anchor)
|
1295
1298
|
end
|
1296
1299
|
|
1297
1300
|
def root(options={})
|
@@ -1347,7 +1350,7 @@ module ActionDispatch
|
|
1347
1350
|
end
|
1348
1351
|
|
1349
1352
|
def scope_action_options? #:nodoc:
|
1350
|
-
@scope[:options]
|
1353
|
+
@scope[:options] && (@scope[:options][:only] || @scope[:options][:except])
|
1351
1354
|
end
|
1352
1355
|
|
1353
1356
|
def scope_action_options #:nodoc:
|
@@ -1355,11 +1358,11 @@ module ActionDispatch
|
|
1355
1358
|
end
|
1356
1359
|
|
1357
1360
|
def resource_scope? #:nodoc:
|
1358
|
-
|
1361
|
+
[:resource, :resources].include? @scope[:scope_level]
|
1359
1362
|
end
|
1360
1363
|
|
1361
1364
|
def resource_method_scope? #:nodoc:
|
1362
|
-
|
1365
|
+
[:collection, :member, :new].include? @scope[:scope_level]
|
1363
1366
|
end
|
1364
1367
|
|
1365
1368
|
def with_exclusive_scope
|
@@ -1384,8 +1387,8 @@ module ActionDispatch
|
|
1384
1387
|
@scope[:scope_level_resource] = old_resource
|
1385
1388
|
end
|
1386
1389
|
|
1387
|
-
def resource_scope(resource) #:nodoc:
|
1388
|
-
with_scope_level(
|
1390
|
+
def resource_scope(kind, resource) #:nodoc:
|
1391
|
+
with_scope_level(kind, resource) do
|
1389
1392
|
scope(parent_resource.resource_scope) do
|
1390
1393
|
yield
|
1391
1394
|
end
|
@@ -1393,10 +1396,12 @@ module ActionDispatch
|
|
1393
1396
|
end
|
1394
1397
|
|
1395
1398
|
def nested_options #:nodoc:
|
1396
|
-
{
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1399
|
+
options = { :as => parent_resource.member_name }
|
1400
|
+
options[:constraints] = {
|
1401
|
+
:"#{parent_resource.singular}_id" => id_constraint
|
1402
|
+
} if id_constraint?
|
1403
|
+
|
1404
|
+
options
|
1400
1405
|
end
|
1401
1406
|
|
1402
1407
|
def id_constraint? #:nodoc:
|
@@ -1427,7 +1432,9 @@ module ActionDispatch
|
|
1427
1432
|
end
|
1428
1433
|
|
1429
1434
|
def action_path(name, path = nil) #:nodoc:
|
1430
|
-
|
1435
|
+
# Ruby 1.8 can't transform empty strings to symbols
|
1436
|
+
name = name.to_sym if name.is_a?(String) && !name.empty?
|
1437
|
+
path || @scope[:path_names][name] || name.to_s
|
1431
1438
|
end
|
1432
1439
|
|
1433
1440
|
def prefix_name_for_action(as, action) #:nodoc:
|
@@ -1444,7 +1451,7 @@ module ActionDispatch
|
|
1444
1451
|
name_prefix = @scope[:as]
|
1445
1452
|
|
1446
1453
|
if parent_resource
|
1447
|
-
return nil
|
1454
|
+
return nil unless as || action
|
1448
1455
|
|
1449
1456
|
collection_name = parent_resource.collection_name
|
1450
1457
|
member_name = parent_resource.member_name
|
@@ -1465,22 +1472,17 @@ module ActionDispatch
|
|
1465
1472
|
[name_prefix, member_name, prefix]
|
1466
1473
|
end
|
1467
1474
|
|
1468
|
-
candidate = name.select(&:present?).join("_").presence
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
options.merge!(:to => to).delete(path)
|
1479
|
-
super(path, options)
|
1480
|
-
else
|
1481
|
-
super
|
1475
|
+
if candidate = name.select(&:present?).join("_").presence
|
1476
|
+
# If a name was not explicitly given, we check if it is valid
|
1477
|
+
# and return nil in case it isn't. Otherwise, we pass the invalid name
|
1478
|
+
# forward so the underlying router engine treats it and raises an exception.
|
1479
|
+
if as.nil?
|
1480
|
+
candidate unless @set.routes.find { |r| r.name == candidate } || candidate !~ /\A[_a-z]/i
|
1481
|
+
else
|
1482
|
+
candidate
|
1483
|
+
end
|
1484
|
+
end
|
1482
1485
|
end
|
1483
|
-
end
|
1484
1486
|
end
|
1485
1487
|
|
1486
1488
|
def initialize(set) #:nodoc:
|
@@ -1493,7 +1495,6 @@ module ActionDispatch
|
|
1493
1495
|
include Redirection
|
1494
1496
|
include Scoping
|
1495
1497
|
include Resources
|
1496
|
-
include Shorthand
|
1497
1498
|
end
|
1498
1499
|
end
|
1499
1500
|
end
|