actionpack 3.0.0.rc → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +11 -16
- data/README.rdoc +3 -3
- data/lib/abstract_controller/base.rb +28 -14
- data/lib/abstract_controller/callbacks.rb +22 -23
- data/lib/abstract_controller/helpers.rb +24 -7
- data/lib/abstract_controller/layouts.rb +12 -10
- data/lib/abstract_controller/view_paths.rb +7 -7
- data/lib/abstract_controller.rb +1 -0
- data/lib/action_controller/base.rb +165 -2
- 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 +2 -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_controller.rb +2 -1
- data/lib/action_dispatch/http/cache.rb +2 -2
- data/lib/action_dispatch/http/mime_negotiation.rb +1 -1
- 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 +12 -2
- data/lib/action_dispatch/middleware/best_standards_support.rb +22 -0
- data/lib/action_dispatch/middleware/cookies.rb +29 -10
- data/lib/action_dispatch/middleware/flash.rb +7 -2
- 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/deprecated_mapper.rb +1 -0
- data/lib/action_dispatch/routing/mapper.rb +120 -137
- data/lib/action_dispatch/routing/polymorphic_routes.rb +10 -10
- data/lib/action_dispatch/routing/route_set.rb +8 -5
- data/lib/action_dispatch/routing/url_for.rb +1 -1
- data/lib/action_dispatch/routing.rb +4 -4
- data/lib/action_dispatch/testing/assertions/dom.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +5 -5
- data/lib/action_dispatch/testing/assertions/routing.rb +39 -16
- data/lib/action_dispatch/testing/integration.rb +1 -0
- data/lib/action_dispatch.rb +1 -0
- data/lib/action_pack/version.rb +1 -2
- data/lib/action_view/base.rb +1 -0
- data/lib/action_view/helpers/asset_tag_helper.rb +12 -0
- data/lib/action_view/helpers/capture_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +13 -17
- data/lib/action_view/helpers/debug_helper.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +16 -10
- 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/helpers/url_helper.rb +2 -2
- 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/template.rb +3 -3
- data/lib/action_view/test_case.rb +1 -1
- data/lib/action_view/testing/resolvers.rb +1 -1
- metadata +20 -23
|
@@ -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,21 +26,27 @@ 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:
|
|
38
44
|
IGNORE_OPTIONS = [:to, :as, :via, :on, :constraints, :defaults, :only, :except, :anchor, :shallow, :shallow_path, :shallow_prefix]
|
|
39
45
|
|
|
40
|
-
def initialize(set, scope,
|
|
41
|
-
@set, @scope
|
|
42
|
-
@
|
|
46
|
+
def initialize(set, scope, path, options)
|
|
47
|
+
@set, @scope = set, scope
|
|
48
|
+
@options = (@scope[:options] || {}).merge(options)
|
|
49
|
+
@path = normalize_path(path)
|
|
43
50
|
normalize_options!
|
|
44
51
|
end
|
|
45
52
|
|
|
@@ -48,28 +55,6 @@ module ActionDispatch
|
|
|
48
55
|
end
|
|
49
56
|
|
|
50
57
|
private
|
|
51
|
-
def extract_path_and_options(args)
|
|
52
|
-
options = args.extract_options!
|
|
53
|
-
|
|
54
|
-
if using_to_shorthand?(args, options)
|
|
55
|
-
path, to = options.find { |name, value| name.is_a?(String) }
|
|
56
|
-
options.merge!(:to => to).delete(path) if path
|
|
57
|
-
else
|
|
58
|
-
path = args.first
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
if path.match(':controller')
|
|
62
|
-
raise ArgumentError, ":controller segment is not allowed within a namespace block" if @scope[:module]
|
|
63
|
-
|
|
64
|
-
# Add a default constraint for :controller path segments that matches namespaced
|
|
65
|
-
# controllers with default routes like :controller/:action/:id(.:format), e.g:
|
|
66
|
-
# GET /admin/products/show/1
|
|
67
|
-
# => { :controller => 'admin/products', :action => 'show', :id => '1' }
|
|
68
|
-
options.reverse_merge!(:controller => /.+?/)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
[ normalize_path(path), options ]
|
|
72
|
-
end
|
|
73
58
|
|
|
74
59
|
def normalize_options!
|
|
75
60
|
path_without_format = @path.sub(/\(\.:format\)$/, '')
|
|
@@ -77,25 +62,39 @@ module ActionDispatch
|
|
|
77
62
|
if using_match_shorthand?(path_without_format, @options)
|
|
78
63
|
to_shorthand = @options[:to].blank?
|
|
79
64
|
@options[:to] ||= path_without_format[1..-1].sub(%r{/([^/]*)$}, '#\1')
|
|
80
|
-
@options[:as] ||=
|
|
65
|
+
@options[:as] ||= Mapper.normalize_name(path_without_format)
|
|
81
66
|
end
|
|
82
67
|
|
|
83
68
|
@options.merge!(default_controller_and_action(to_shorthand))
|
|
84
69
|
end
|
|
85
70
|
|
|
86
|
-
# match "account" => "account#index"
|
|
87
|
-
def using_to_shorthand?(args, options)
|
|
88
|
-
args.empty? && options.present?
|
|
89
|
-
end
|
|
90
|
-
|
|
91
71
|
# match "account/overview"
|
|
92
72
|
def using_match_shorthand?(path, options)
|
|
93
73
|
path && options.except(:via, :anchor, :to, :as).empty? && path =~ %r{^/[\w\/]+$}
|
|
94
74
|
end
|
|
95
75
|
|
|
96
76
|
def normalize_path(path)
|
|
97
|
-
raise ArgumentError, "path is required" if
|
|
98
|
-
Mapper.normalize_path(
|
|
77
|
+
raise ArgumentError, "path is required" if path.blank?
|
|
78
|
+
path = Mapper.normalize_path(path)
|
|
79
|
+
|
|
80
|
+
if path.match(':controller')
|
|
81
|
+
raise ArgumentError, ":controller segment is not allowed within a namespace block" if @scope[:module]
|
|
82
|
+
|
|
83
|
+
# Add a default constraint for :controller path segments that matches namespaced
|
|
84
|
+
# controllers with default routes like :controller/:action/:id(.:format), e.g:
|
|
85
|
+
# GET /admin/products/show/1
|
|
86
|
+
# => { :controller => 'admin/products', :action => 'show', :id => '1' }
|
|
87
|
+
@options.reverse_merge!(:controller => /.+?/)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
if @options[:format] == false
|
|
91
|
+
@options.delete(:format)
|
|
92
|
+
path
|
|
93
|
+
elsif path.include?(":format")
|
|
94
|
+
path
|
|
95
|
+
else
|
|
96
|
+
"#{path}(.:format)"
|
|
97
|
+
end
|
|
99
98
|
end
|
|
100
99
|
|
|
101
100
|
def app
|
|
@@ -218,6 +217,10 @@ module ActionDispatch
|
|
|
218
217
|
path
|
|
219
218
|
end
|
|
220
219
|
|
|
220
|
+
def self.normalize_name(name)
|
|
221
|
+
normalize_path(name)[1..-1].gsub("/", "_")
|
|
222
|
+
end
|
|
223
|
+
|
|
221
224
|
module Base
|
|
222
225
|
def initialize(set) #:nodoc:
|
|
223
226
|
@set = set
|
|
@@ -227,8 +230,8 @@ module ActionDispatch
|
|
|
227
230
|
match '/', options.reverse_merge(:as => :root)
|
|
228
231
|
end
|
|
229
232
|
|
|
230
|
-
def match(
|
|
231
|
-
mapping = Mapping.new(@set, @scope,
|
|
233
|
+
def match(path, options=nil)
|
|
234
|
+
mapping = Mapping.new(@set, @scope, path, options || {}).to_route
|
|
232
235
|
@set.add_route(*mapping)
|
|
233
236
|
self
|
|
234
237
|
end
|
|
@@ -244,7 +247,7 @@ module ActionDispatch
|
|
|
244
247
|
|
|
245
248
|
raise "A rack application must be specified" unless path
|
|
246
249
|
|
|
247
|
-
match(path, options.merge(:to => app, :anchor => false))
|
|
250
|
+
match(path, options.merge(:to => app, :anchor => false, :format => false))
|
|
248
251
|
self
|
|
249
252
|
end
|
|
250
253
|
|
|
@@ -277,7 +280,6 @@ module ActionDispatch
|
|
|
277
280
|
path = args.shift || block
|
|
278
281
|
path_proc = path.is_a?(Proc) ? path : proc { |params| path % params }
|
|
279
282
|
status = options[:status] || 301
|
|
280
|
-
body = 'Moved Permanently'
|
|
281
283
|
|
|
282
284
|
lambda do |env|
|
|
283
285
|
req = Request.new(env)
|
|
@@ -288,13 +290,16 @@ module ActionDispatch
|
|
|
288
290
|
uri = URI.parse(path_proc.call(*params))
|
|
289
291
|
uri.scheme ||= req.scheme
|
|
290
292
|
uri.host ||= req.host
|
|
291
|
-
uri.port ||= req.port unless req.
|
|
293
|
+
uri.port ||= req.port unless req.standard_port?
|
|
294
|
+
|
|
295
|
+
body = %(<html><body>You are being <a href="#{ERB::Util.h(uri.to_s)}">redirected</a>.</body></html>)
|
|
292
296
|
|
|
293
297
|
headers = {
|
|
294
298
|
'Location' => uri.to_s,
|
|
295
299
|
'Content-Type' => 'text/html',
|
|
296
300
|
'Content-Length' => body.length.to_s
|
|
297
301
|
}
|
|
302
|
+
|
|
298
303
|
[ status, headers, [body] ]
|
|
299
304
|
end
|
|
300
305
|
end
|
|
@@ -324,13 +329,7 @@ module ActionDispatch
|
|
|
324
329
|
ActiveSupport::Deprecation.warn ":name_prefix was deprecated in the new router syntax. Use :as instead.", caller
|
|
325
330
|
end
|
|
326
331
|
|
|
327
|
-
|
|
328
|
-
when String
|
|
329
|
-
options[:path] = args.first
|
|
330
|
-
when Symbol
|
|
331
|
-
options[:controller] = args.first
|
|
332
|
-
end
|
|
333
|
-
|
|
332
|
+
options[:path] = args.first if args.first.is_a?(String)
|
|
334
333
|
recover = {}
|
|
335
334
|
|
|
336
335
|
options[:constraints] ||= {}
|
|
@@ -362,8 +361,9 @@ module ActionDispatch
|
|
|
362
361
|
@scope[:blocks] = recover[:block]
|
|
363
362
|
end
|
|
364
363
|
|
|
365
|
-
def controller(controller)
|
|
366
|
-
|
|
364
|
+
def controller(controller, options={})
|
|
365
|
+
options[:controller] = controller
|
|
366
|
+
scope(options) { yield }
|
|
367
367
|
end
|
|
368
368
|
|
|
369
369
|
def namespace(path, options = {})
|
|
@@ -381,21 +381,6 @@ module ActionDispatch
|
|
|
381
381
|
scope(:defaults => defaults) { yield }
|
|
382
382
|
end
|
|
383
383
|
|
|
384
|
-
def match(*args)
|
|
385
|
-
options = args.extract_options!
|
|
386
|
-
|
|
387
|
-
options = (@scope[:options] || {}).merge(options)
|
|
388
|
-
|
|
389
|
-
if @scope[:as] && !options[:as].blank?
|
|
390
|
-
options[:as] = "#{@scope[:as]}_#{options[:as]}"
|
|
391
|
-
elsif @scope[:as] && options[:as] == ""
|
|
392
|
-
options[:as] = @scope[:as].to_s
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
args.push(options)
|
|
396
|
-
super(*args)
|
|
397
|
-
end
|
|
398
|
-
|
|
399
384
|
private
|
|
400
385
|
def scope_options
|
|
401
386
|
@scope_options ||= private_methods.grep(/^merge_(.+)_scope$/) { $1.to_sym }
|
|
@@ -459,9 +444,9 @@ module ActionDispatch
|
|
|
459
444
|
module Resources
|
|
460
445
|
# CANONICAL_ACTIONS holds all actions that does not need a prefix or
|
|
461
446
|
# a path appended since they fit properly in their scope level.
|
|
462
|
-
VALID_ON_OPTIONS
|
|
463
|
-
|
|
464
|
-
|
|
447
|
+
VALID_ON_OPTIONS = [:new, :collection, :member]
|
|
448
|
+
RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except]
|
|
449
|
+
CANONICAL_ACTIONS = %w(index create new show update destroy)
|
|
465
450
|
|
|
466
451
|
class Resource #:nodoc:
|
|
467
452
|
DEFAULT_ACTIONS = [:index, :create, :new, :show, :update, :destroy, :edit]
|
|
@@ -470,7 +455,7 @@ module ActionDispatch
|
|
|
470
455
|
|
|
471
456
|
def initialize(entities, options = {})
|
|
472
457
|
@name = entities.to_s
|
|
473
|
-
@path = options.delete(:path) || @name
|
|
458
|
+
@path = (options.delete(:path) || @name).to_s
|
|
474
459
|
@controller = (options.delete(:controller) || @name).to_s
|
|
475
460
|
@as = options.delete(:as)
|
|
476
461
|
@options = options
|
|
@@ -495,16 +480,14 @@ module ActionDispatch
|
|
|
495
480
|
end
|
|
496
481
|
|
|
497
482
|
def plural
|
|
498
|
-
name.to_s
|
|
483
|
+
@plural ||= name.to_s
|
|
499
484
|
end
|
|
500
485
|
|
|
501
486
|
def singular
|
|
502
|
-
name.to_s.singularize
|
|
487
|
+
@singular ||= name.to_s.singularize
|
|
503
488
|
end
|
|
504
489
|
|
|
505
|
-
|
|
506
|
-
singular
|
|
507
|
-
end
|
|
490
|
+
alias :member_name :singular
|
|
508
491
|
|
|
509
492
|
# Checks for uncountable plurals, and appends "_index" if they're.
|
|
510
493
|
def collection_name
|
|
@@ -515,9 +498,7 @@ module ActionDispatch
|
|
|
515
498
|
{ :controller => controller }
|
|
516
499
|
end
|
|
517
500
|
|
|
518
|
-
|
|
519
|
-
path
|
|
520
|
-
end
|
|
501
|
+
alias :collection_scope :path
|
|
521
502
|
|
|
522
503
|
def member_scope
|
|
523
504
|
"#{path}/:id"
|
|
@@ -538,21 +519,25 @@ module ActionDispatch
|
|
|
538
519
|
|
|
539
520
|
def initialize(entities, options)
|
|
540
521
|
@name = entities.to_s
|
|
541
|
-
@path = options.delete(:path) || @name
|
|
522
|
+
@path = (options.delete(:path) || @name).to_s
|
|
542
523
|
@controller = (options.delete(:controller) || plural).to_s
|
|
543
524
|
@as = options.delete(:as)
|
|
544
525
|
@options = options
|
|
545
526
|
end
|
|
546
527
|
|
|
547
|
-
def
|
|
548
|
-
name
|
|
528
|
+
def plural
|
|
529
|
+
@plural ||= name.to_s.pluralize
|
|
549
530
|
end
|
|
550
|
-
alias :collection_name :member_name
|
|
551
531
|
|
|
552
|
-
def
|
|
553
|
-
|
|
532
|
+
def singular
|
|
533
|
+
@singular ||= name.to_s
|
|
554
534
|
end
|
|
555
|
-
|
|
535
|
+
|
|
536
|
+
alias :member_name :singular
|
|
537
|
+
alias :collection_name :singular
|
|
538
|
+
|
|
539
|
+
alias :member_scope :path
|
|
540
|
+
alias :nested_scope :path
|
|
556
541
|
end
|
|
557
542
|
|
|
558
543
|
def initialize(*args) #:nodoc:
|
|
@@ -583,10 +568,10 @@ module ActionDispatch
|
|
|
583
568
|
end if parent_resource.actions.include?(:new)
|
|
584
569
|
|
|
585
570
|
member_scope do
|
|
571
|
+
get :edit if parent_resource.actions.include?(:edit)
|
|
586
572
|
get :show if parent_resource.actions.include?(:show)
|
|
587
573
|
put :update if parent_resource.actions.include?(:update)
|
|
588
574
|
delete :destroy if parent_resource.actions.include?(:destroy)
|
|
589
|
-
get :edit if parent_resource.actions.include?(:edit)
|
|
590
575
|
end
|
|
591
576
|
end
|
|
592
577
|
|
|
@@ -613,10 +598,10 @@ module ActionDispatch
|
|
|
613
598
|
end if parent_resource.actions.include?(:new)
|
|
614
599
|
|
|
615
600
|
member_scope do
|
|
601
|
+
get :edit if parent_resource.actions.include?(:edit)
|
|
616
602
|
get :show if parent_resource.actions.include?(:show)
|
|
617
603
|
put :update if parent_resource.actions.include?(:update)
|
|
618
604
|
delete :destroy if parent_resource.actions.include?(:destroy)
|
|
619
|
-
get :edit if parent_resource.actions.include?(:edit)
|
|
620
605
|
end
|
|
621
606
|
end
|
|
622
607
|
|
|
@@ -710,46 +695,31 @@ module ActionDispatch
|
|
|
710
695
|
raise ArgumentError, "Unknown scope #{on.inspect} given to :on"
|
|
711
696
|
end
|
|
712
697
|
|
|
713
|
-
if @scope[:scope_level] == :
|
|
698
|
+
if @scope[:scope_level] == :resources
|
|
699
|
+
args.push(options)
|
|
700
|
+
return nested { match(*args) }
|
|
701
|
+
elsif @scope[:scope_level] == :resource
|
|
714
702
|
args.push(options)
|
|
715
703
|
return member { match(*args) }
|
|
716
704
|
end
|
|
717
705
|
|
|
718
|
-
path = options.delete(:path)
|
|
719
706
|
action = args.first
|
|
707
|
+
path = path_for_action(action, options.delete(:path))
|
|
720
708
|
|
|
721
|
-
if action.
|
|
722
|
-
|
|
723
|
-
options[:
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
with_exclusive_scope do
|
|
727
|
-
return super(path, options)
|
|
728
|
-
end
|
|
729
|
-
elsif resource_method_scope?
|
|
730
|
-
path = path_for_custom_action
|
|
731
|
-
options[:as] = name_for_action(options[:as]) if options[:as]
|
|
732
|
-
args.push(options)
|
|
733
|
-
|
|
734
|
-
with_exclusive_scope do
|
|
735
|
-
scope(path) do
|
|
736
|
-
return super
|
|
737
|
-
end
|
|
738
|
-
end
|
|
739
|
-
end
|
|
740
|
-
|
|
741
|
-
if resource_scope?
|
|
742
|
-
raise ArgumentError, "can't define route directly in resource(s) scope"
|
|
709
|
+
if action.to_s =~ /^[\w\/]+$/
|
|
710
|
+
options[:action] ||= action unless action.to_s.include?("/")
|
|
711
|
+
options[:as] = name_for_action(action, options[:as])
|
|
712
|
+
else
|
|
713
|
+
options[:as] = name_for_action(options[:as])
|
|
743
714
|
end
|
|
744
715
|
|
|
745
|
-
|
|
746
|
-
super
|
|
716
|
+
super(path, options)
|
|
747
717
|
end
|
|
748
718
|
|
|
749
719
|
def root(options={})
|
|
750
720
|
if @scope[:scope_level] == :resources
|
|
751
|
-
with_scope_level(:
|
|
752
|
-
scope(parent_resource.path
|
|
721
|
+
with_scope_level(:root) do
|
|
722
|
+
scope(parent_resource.path) do
|
|
753
723
|
super(options)
|
|
754
724
|
end
|
|
755
725
|
end
|
|
@@ -770,6 +740,10 @@ module ActionDispatch
|
|
|
770
740
|
return true
|
|
771
741
|
end
|
|
772
742
|
|
|
743
|
+
options.keys.each do |k|
|
|
744
|
+
(options[:constraints] ||= {})[k] = options.delete(k) if options[k].is_a?(Regexp)
|
|
745
|
+
end
|
|
746
|
+
|
|
773
747
|
scope_options = options.slice!(*RESOURCE_OPTIONS)
|
|
774
748
|
unless scope_options.empty?
|
|
775
749
|
scope(scope_options) do
|
|
@@ -882,7 +856,7 @@ module ActionDispatch
|
|
|
882
856
|
end
|
|
883
857
|
|
|
884
858
|
def canonical_action?(action, flag)
|
|
885
|
-
flag && CANONICAL_ACTIONS.include?(action)
|
|
859
|
+
flag && resource_method_scope? && CANONICAL_ACTIONS.include?(action.to_s)
|
|
886
860
|
end
|
|
887
861
|
|
|
888
862
|
def shallow_scoping?
|
|
@@ -893,18 +867,10 @@ module ActionDispatch
|
|
|
893
867
|
prefix = shallow_scoping? ?
|
|
894
868
|
"#{@scope[:shallow_path]}/#{parent_resource.path}/:id" : @scope[:path]
|
|
895
869
|
|
|
896
|
-
if canonical_action?(action, path.blank?)
|
|
897
|
-
|
|
898
|
-
else
|
|
899
|
-
"#{prefix}/#{action_path(action, path)}(.:format)"
|
|
900
|
-
end
|
|
901
|
-
end
|
|
902
|
-
|
|
903
|
-
def path_for_custom_action
|
|
904
|
-
if shallow_scoping?
|
|
905
|
-
"#{@scope[:shallow_path]}/#{parent_resource.path}/:id"
|
|
870
|
+
path = if canonical_action?(action, path.blank?)
|
|
871
|
+
prefix.to_s
|
|
906
872
|
else
|
|
907
|
-
|
|
873
|
+
"#{prefix}/#{action_path(action, path)}"
|
|
908
874
|
end
|
|
909
875
|
end
|
|
910
876
|
|
|
@@ -914,44 +880,61 @@ module ActionDispatch
|
|
|
914
880
|
|
|
915
881
|
def prefix_name_for_action(action, as)
|
|
916
882
|
if as.present?
|
|
917
|
-
|
|
883
|
+
as.to_s
|
|
918
884
|
elsif as
|
|
919
|
-
|
|
885
|
+
nil
|
|
920
886
|
elsif !canonical_action?(action, @scope[:scope_level])
|
|
921
|
-
|
|
887
|
+
action.to_s
|
|
922
888
|
end
|
|
923
889
|
end
|
|
924
890
|
|
|
925
891
|
def name_for_action(action, as=nil)
|
|
926
892
|
prefix = prefix_name_for_action(action, as)
|
|
893
|
+
prefix = Mapper.normalize_name(prefix) if prefix
|
|
927
894
|
name_prefix = @scope[:as]
|
|
928
895
|
|
|
929
896
|
if parent_resource
|
|
930
897
|
collection_name = parent_resource.collection_name
|
|
931
898
|
member_name = parent_resource.member_name
|
|
932
|
-
name_prefix = "#{name_prefix}_" if name_prefix.present?
|
|
933
899
|
end
|
|
934
900
|
|
|
935
|
-
case @scope[:scope_level]
|
|
901
|
+
name = case @scope[:scope_level]
|
|
902
|
+
when :nested
|
|
903
|
+
[member_name, prefix]
|
|
936
904
|
when :collection
|
|
937
|
-
|
|
905
|
+
[prefix, name_prefix, collection_name]
|
|
938
906
|
when :new
|
|
939
|
-
|
|
907
|
+
[prefix, :new, name_prefix, member_name]
|
|
908
|
+
when :member
|
|
909
|
+
[prefix, shallow_scoping? ? @scope[:shallow_prefix] : name_prefix, member_name]
|
|
910
|
+
when :root
|
|
911
|
+
[name_prefix, collection_name, prefix]
|
|
940
912
|
else
|
|
941
|
-
|
|
942
|
-
shallow_prefix = "#{@scope[:shallow_prefix]}_" if @scope[:shallow_prefix].present?
|
|
943
|
-
"#{prefix}#{shallow_prefix}#{member_name}"
|
|
944
|
-
else
|
|
945
|
-
"#{prefix}#{name_prefix}#{member_name}"
|
|
946
|
-
end
|
|
913
|
+
[name_prefix, member_name, prefix]
|
|
947
914
|
end
|
|
915
|
+
|
|
916
|
+
name.select(&:present?).join("_").presence
|
|
948
917
|
end
|
|
949
918
|
end
|
|
950
919
|
|
|
920
|
+
module Shorthand
|
|
921
|
+
def match(*args)
|
|
922
|
+
if args.size == 1 && args.last.is_a?(Hash)
|
|
923
|
+
options = args.pop
|
|
924
|
+
path, to = options.find { |name, value| name.is_a?(String) }
|
|
925
|
+
options.merge!(:to => to).delete(path)
|
|
926
|
+
super(path, options)
|
|
927
|
+
else
|
|
928
|
+
super
|
|
929
|
+
end
|
|
930
|
+
end
|
|
931
|
+
end
|
|
932
|
+
|
|
951
933
|
include Base
|
|
952
934
|
include HttpHelpers
|
|
953
935
|
include Scoping
|
|
954
936
|
include Resources
|
|
937
|
+
include Shorthand
|
|
955
938
|
end
|
|
956
939
|
end
|
|
957
940
|
end
|
|
@@ -148,29 +148,29 @@ module ActionDispatch
|
|
|
148
148
|
def build_named_route_call(records, inflection, options = {})
|
|
149
149
|
unless records.is_a?(Array)
|
|
150
150
|
record = extract_record(records)
|
|
151
|
-
route =
|
|
151
|
+
route = []
|
|
152
152
|
else
|
|
153
153
|
record = records.pop
|
|
154
|
-
route = records.
|
|
154
|
+
route = records.map do |parent|
|
|
155
155
|
if parent.is_a?(Symbol) || parent.is_a?(String)
|
|
156
|
-
|
|
156
|
+
parent
|
|
157
157
|
else
|
|
158
|
-
|
|
159
|
-
string << "_"
|
|
158
|
+
ActiveModel::Naming.plural(parent).singularize
|
|
160
159
|
end
|
|
161
160
|
end
|
|
162
161
|
end
|
|
163
162
|
|
|
164
163
|
if record.is_a?(Symbol) || record.is_a?(String)
|
|
165
|
-
route <<
|
|
164
|
+
route << record
|
|
166
165
|
else
|
|
167
166
|
route << ActiveModel::Naming.plural(record)
|
|
168
|
-
route = route.singularize if inflection == :singular
|
|
169
|
-
route << "
|
|
170
|
-
route << "index_" if ActiveModel::Naming.uncountable?(record) && inflection == :plural
|
|
167
|
+
route = [route.join("_").singularize] if inflection == :singular
|
|
168
|
+
route << "index" if ActiveModel::Naming.uncountable?(record) && inflection == :plural
|
|
171
169
|
end
|
|
172
170
|
|
|
173
|
-
|
|
171
|
+
route << routing_type(options)
|
|
172
|
+
|
|
173
|
+
action_prefix(options) + route.join("_")
|
|
174
174
|
end
|
|
175
175
|
|
|
176
176
|
def extract_record(record_or_hash_or_array)
|
|
@@ -392,10 +392,9 @@ module ActionDispatch
|
|
|
392
392
|
end
|
|
393
393
|
|
|
394
394
|
def generate
|
|
395
|
-
error = ActionController::RoutingError.new("No route matches #{options.inspect}")
|
|
396
395
|
path, params = @set.set.generate(:path_info, named_route, options, recall, opts)
|
|
397
396
|
|
|
398
|
-
|
|
397
|
+
raise_routing_error unless path
|
|
399
398
|
|
|
400
399
|
params.reject! {|k,v| !v }
|
|
401
400
|
|
|
@@ -404,7 +403,7 @@ module ActionDispatch
|
|
|
404
403
|
path << "?#{params.to_query}" if params.any?
|
|
405
404
|
"#{script_name}#{path}"
|
|
406
405
|
rescue Rack::Mount::RoutingError
|
|
407
|
-
|
|
406
|
+
raise_routing_error
|
|
408
407
|
end
|
|
409
408
|
|
|
410
409
|
def opts
|
|
@@ -421,6 +420,10 @@ module ActionDispatch
|
|
|
421
420
|
{:parameterize => parameterize}
|
|
422
421
|
end
|
|
423
422
|
|
|
423
|
+
def raise_routing_error
|
|
424
|
+
raise ActionController::RoutingError.new("No route matches #{options.inspect}")
|
|
425
|
+
end
|
|
426
|
+
|
|
424
427
|
def different_controller?
|
|
425
428
|
return false unless current_controller
|
|
426
429
|
controller.to_param != current_controller.to_param
|
|
@@ -491,7 +494,7 @@ module ActionDispatch
|
|
|
491
494
|
|
|
492
495
|
def recognize_path(path, environment = {})
|
|
493
496
|
method = (environment[:method] || "GET").to_s.upcase
|
|
494
|
-
path = Rack::Mount::Utils.normalize_path(path)
|
|
497
|
+
path = Rack::Mount::Utils.normalize_path(path) unless path =~ %r{://}
|
|
495
498
|
|
|
496
499
|
begin
|
|
497
500
|
env = Rack::MockRequest.env_for(path, {:method => method})
|
|
@@ -499,7 +502,7 @@ module ActionDispatch
|
|
|
499
502
|
raise ActionController::RoutingError, e.message
|
|
500
503
|
end
|
|
501
504
|
|
|
502
|
-
req =
|
|
505
|
+
req = @request_class.new(env)
|
|
503
506
|
@set.recognize(req) do |route, matches, params|
|
|
504
507
|
params.each do |key, value|
|
|
505
508
|
if value.is_a?(String)
|
|
@@ -20,7 +20,7 @@ module ActionDispatch
|
|
|
20
20
|
# <%= link_to('Click here', :controller => 'users',
|
|
21
21
|
# :action => 'new', :message => 'Welcome!') %>
|
|
22
22
|
#
|
|
23
|
-
#
|
|
23
|
+
# # Generates a link to /users/new?message=Welcome%21
|
|
24
24
|
#
|
|
25
25
|
# link_to, and all other functions that require URL generation functionality,
|
|
26
26
|
# actually use ActionController::UrlFor under the hood. And in particular,
|
|
@@ -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
|
#
|
|
@@ -3,7 +3,7 @@ require 'action_controller/vendor/html-scanner'
|
|
|
3
3
|
module ActionDispatch
|
|
4
4
|
module Assertions
|
|
5
5
|
module DomAssertions
|
|
6
|
-
# Test two HTML strings for equivalency (e.g., identical up to reordering of attributes)
|
|
6
|
+
# \Test two HTML strings for equivalency (e.g., identical up to reordering of attributes)
|
|
7
7
|
#
|
|
8
8
|
# ==== Examples
|
|
9
9
|
#
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module ActionDispatch
|
|
2
2
|
module Assertions
|
|
3
|
-
# A small suite of assertions that test responses from Rails applications.
|
|
3
|
+
# A small suite of assertions that test responses from \Rails applications.
|
|
4
4
|
module ResponseAssertions
|
|
5
5
|
extend ActiveSupport::Concern
|
|
6
6
|
|
|
@@ -18,8 +18,8 @@ module ActionDispatch
|
|
|
18
18
|
# * <tt>:missing</tt> - Status code was 404
|
|
19
19
|
# * <tt>:error</tt> - Status code was in the 500-599 range
|
|
20
20
|
#
|
|
21
|
-
# You can also pass an explicit status number like assert_response(501)
|
|
22
|
-
# or its symbolic equivalent assert_response(:not_implemented)
|
|
21
|
+
# You can also pass an explicit status number like <tt>assert_response(501)</tt>
|
|
22
|
+
# or its symbolic equivalent <tt>assert_response(:not_implemented)</tt>.
|
|
23
23
|
# See ActionDispatch::StatusCodes for a full list.
|
|
24
24
|
#
|
|
25
25
|
# ==== Examples
|
|
@@ -45,8 +45,8 @@ module ActionDispatch
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
# Assert that the redirection options passed in match those of the redirect called in the latest action.
|
|
48
|
-
# This match can be partial, such that assert_redirected_to(:controller => "weblog") will also
|
|
49
|
-
# match the redirection of redirect_to(:controller => "weblog", :action => "show") and so on.
|
|
48
|
+
# This match can be partial, such that <tt>assert_redirected_to(:controller => "weblog")</tt> will also
|
|
49
|
+
# match the redirection of <tt>redirect_to(:controller => "weblog", :action => "show")</tt> and so on.
|
|
50
50
|
#
|
|
51
51
|
# ==== Examples
|
|
52
52
|
#
|