actionpack 3.0.0.beta3 → 3.0.0.beta4

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.

Files changed (83) hide show
  1. data/CHANGELOG +19 -0
  2. data/lib/abstract_controller.rb +1 -1
  3. data/lib/abstract_controller/asset_paths.rb +9 -0
  4. data/lib/abstract_controller/base.rb +5 -13
  5. data/lib/abstract_controller/callbacks.rb +1 -1
  6. data/lib/abstract_controller/helpers.rb +0 -1
  7. data/lib/abstract_controller/layouts.rb +3 -3
  8. data/lib/abstract_controller/logger.rb +1 -1
  9. data/lib/abstract_controller/rendering.rb +1 -0
  10. data/lib/action_controller/base.rb +5 -1
  11. data/lib/action_controller/caching.rb +2 -3
  12. data/lib/action_controller/caching/actions.rb +1 -1
  13. data/lib/action_controller/caching/fragments.rb +1 -1
  14. data/lib/action_controller/caching/pages.rb +8 -8
  15. data/lib/action_controller/caching/sweeping.rb +1 -0
  16. data/lib/action_controller/deprecated/base.rb +10 -36
  17. data/lib/action_controller/metal.rb +45 -3
  18. data/lib/action_controller/metal/compatibility.rb +2 -2
  19. data/lib/action_controller/metal/helpers.rb +3 -3
  20. data/lib/action_controller/metal/http_authentication.rb +158 -0
  21. data/lib/action_controller/metal/instrumentation.rb +5 -5
  22. data/lib/action_controller/metal/rack_delegation.rb +4 -4
  23. data/lib/action_controller/metal/renderers.rb +3 -3
  24. data/lib/action_controller/metal/request_forgery_protection.rb +45 -74
  25. data/lib/action_controller/metal/responder.rb +1 -1
  26. data/lib/action_controller/metal/url_for.rb +8 -0
  27. data/lib/action_controller/railtie.rb +26 -39
  28. data/lib/action_controller/test_case.rb +147 -135
  29. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +1 -0
  30. data/lib/action_dispatch.rb +0 -1
  31. data/lib/action_dispatch/http/parameters.rb +2 -1
  32. data/lib/action_dispatch/http/request.rb +19 -7
  33. data/lib/action_dispatch/http/response.rb +3 -33
  34. data/lib/action_dispatch/middleware/cookies.rb +44 -10
  35. data/lib/action_dispatch/middleware/flash.rb +11 -1
  36. data/lib/action_dispatch/middleware/params_parser.rb +3 -1
  37. data/lib/action_dispatch/middleware/session/abstract_store.rb +47 -83
  38. data/lib/action_dispatch/middleware/session/cookie_store.rb +19 -165
  39. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +2 -2
  40. data/lib/action_dispatch/middleware/show_exceptions.rb +18 -12
  41. data/lib/action_dispatch/middleware/stack.rb +17 -67
  42. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +1 -1
  43. data/lib/action_dispatch/railtie.rb +0 -2
  44. data/lib/action_dispatch/routing/deprecated_mapper.rb +1 -0
  45. data/lib/action_dispatch/routing/mapper.rb +89 -23
  46. data/lib/action_dispatch/routing/route_set.rb +22 -16
  47. data/lib/action_dispatch/routing/url_for.rb +1 -1
  48. data/lib/action_dispatch/testing/assertions/routing.rb +1 -0
  49. data/lib/action_dispatch/testing/assertions/selector.rb +11 -7
  50. data/lib/action_dispatch/testing/test_process.rb +3 -2
  51. data/lib/action_pack/version.rb +1 -1
  52. data/lib/action_view.rb +5 -1
  53. data/lib/action_view/base.rb +10 -4
  54. data/lib/action_view/helpers/active_model_helper.rb +1 -8
  55. data/lib/action_view/helpers/asset_tag_helper.rb +7 -4
  56. data/lib/action_view/helpers/cache_helper.rb +14 -14
  57. data/lib/action_view/helpers/capture_helper.rb +25 -6
  58. data/lib/action_view/helpers/date_helper.rb +33 -44
  59. data/lib/action_view/helpers/form_helper.rb +47 -27
  60. data/lib/action_view/helpers/form_options_helper.rb +26 -3
  61. data/lib/action_view/helpers/form_tag_helper.rb +8 -4
  62. data/lib/action_view/helpers/number_helper.rb +5 -2
  63. data/lib/action_view/helpers/prototype_helper.rb +1 -1
  64. data/lib/action_view/helpers/tag_helper.rb +1 -1
  65. data/lib/action_view/helpers/text_helper.rb +55 -46
  66. data/lib/action_view/helpers/translation_helper.rb +19 -8
  67. data/lib/action_view/helpers/url_helper.rb +2 -4
  68. data/lib/action_view/locale/en.yml +14 -14
  69. data/lib/action_view/lookup_context.rb +52 -22
  70. data/lib/action_view/paths.rb +1 -0
  71. data/lib/action_view/render/layouts.rb +3 -12
  72. data/lib/action_view/render/partials.rb +21 -10
  73. data/lib/action_view/render/rendering.rb +1 -1
  74. data/lib/action_view/template.rb +172 -26
  75. data/lib/action_view/template/error.rb +25 -27
  76. data/lib/action_view/template/handlers.rb +1 -1
  77. data/lib/action_view/template/handlers/erb.rb +92 -45
  78. data/lib/action_view/template/resolver.rb +4 -1
  79. data/lib/action_view/test_case.rb +105 -72
  80. data/lib/action_view/testing/resolvers.rb +43 -0
  81. metadata +62 -20
  82. data/lib/abstract_controller/assigns.rb +0 -21
  83. data/lib/action_dispatch/middleware/cascade.rb +0 -29
@@ -38,9 +38,9 @@ module ActionDispatch
38
38
  options = env['rack.session.options']
39
39
  expiry = options[:expire_after] || 0
40
40
  @pool.set(sid, session_data, expiry)
41
- return true
41
+ sid
42
42
  rescue MemCache::MemCacheError, Errno::ECONNREFUSED
43
- return false
43
+ false
44
44
  end
45
45
  end
46
46
  end
@@ -6,7 +6,7 @@ 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.1', '::1'].freeze
9
+ LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze
10
10
 
11
11
  RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
12
12
 
@@ -45,7 +45,17 @@ module ActionDispatch
45
45
  end
46
46
 
47
47
  def call(env)
48
- @app.call(env)
48
+ status, headers, body = @app.call(env)
49
+
50
+ # Only this middleware cares about RoutingError. So, let's just raise
51
+ # it here.
52
+ # TODO: refactor this middleware to handle the X-Cascade scenario without
53
+ # having to raise an exception.
54
+ if headers['X-Cascade'] == 'pass'
55
+ raise ActionController::RoutingError, "No route matches #{env['PATH_INFO'].inspect}"
56
+ end
57
+
58
+ [status, headers, body]
49
59
  rescue Exception => exception
50
60
  raise exception if env['action_dispatch.show_exceptions'] == false
51
61
  render_exception(env, exception)
@@ -62,7 +72,7 @@ module ActionDispatch
62
72
  rescue_action_in_public(exception)
63
73
  end
64
74
  rescue Exception => failsafe_error
65
- $stderr.puts "Error during failsafe response: #{failsafe_error}"
75
+ $stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}"
66
76
  FAILSAFE_RESPONSE
67
77
  end
68
78
 
@@ -104,7 +114,7 @@ module ActionDispatch
104
114
 
105
115
  # True if the request came from localhost, 127.0.0.1.
106
116
  def local_request?(request)
107
- LOCALHOST.any?{ |local_ip| request.remote_addr == local_ip && request.remote_ip == local_ip }
117
+ LOCALHOST.any? { |local_ip| local_ip === request.remote_addr && local_ip === request.remote_ip }
108
118
  end
109
119
 
110
120
  def status_code(exception)
@@ -123,14 +133,10 @@ module ActionDispatch
123
133
  return unless logger
124
134
 
125
135
  ActiveSupport::Deprecation.silence do
126
- if ActionView::Template::Error === exception
127
- logger.fatal(exception.to_s)
128
- else
129
- logger.fatal(
130
- "\n#{exception.class} (#{exception.message}):\n " +
131
- clean_backtrace(exception).join("\n ") + "\n\n"
132
- )
133
- end
136
+ message = "\n#{exception.class} (#{exception.message}):\n"
137
+ message << exception.annoted_source_code if exception.respond_to?(:annoted_source_code)
138
+ message << exception.backtrace.join("\n ")
139
+ logger.fatal("#{message}\n\n")
134
140
  end
135
141
  end
136
142
 
@@ -3,49 +3,15 @@ require "active_support/inflector/methods"
3
3
  module ActionDispatch
4
4
  class MiddlewareStack < Array
5
5
  class Middleware
6
- def self.new(klass, *args, &block)
7
- if klass.is_a?(self)
8
- klass
9
- else
10
- super
11
- end
12
- end
13
-
14
6
  attr_reader :args, :block
15
7
 
16
- def initialize(klass, *args, &block)
17
- @klass = klass
18
-
19
- options = args.extract_options!
20
- if options.has_key?(:if)
21
- @conditional = options.delete(:if)
22
- else
23
- @conditional = true
24
- end
25
- args << options unless options.empty?
26
-
27
- @args = args
28
- @block = block
8
+ def initialize(klass_or_name, *args, &block)
9
+ @ref = ActiveSupport::Dependencies::Reference.new(klass_or_name)
10
+ @args, @block = args, block
29
11
  end
30
12
 
31
13
  def klass
32
- if @klass.respond_to?(:new)
33
- @klass
34
- elsif @klass.respond_to?(:call)
35
- @klass.call
36
- else
37
- ActiveSupport::Inflector.constantize(@klass.to_s)
38
- end
39
- end
40
-
41
- def active?
42
- return false unless klass
43
-
44
- if @conditional.respond_to?(:call)
45
- @conditional.call
46
- else
47
- @conditional
48
- end
14
+ @ref.get
49
15
  end
50
16
 
51
17
  def ==(middleware)
@@ -55,11 +21,7 @@ module ActionDispatch
55
21
  when Class
56
22
  klass == middleware
57
23
  else
58
- if lazy_compare?(@klass) && lazy_compare?(middleware)
59
- normalize(@klass) == normalize(middleware)
60
- else
61
- klass.name == middleware.to_s
62
- end
24
+ normalize(@ref.name) == normalize(middleware)
63
25
  end
64
26
  end
65
27
 
@@ -68,25 +30,14 @@ module ActionDispatch
68
30
  end
69
31
 
70
32
  def build(app)
71
- if block
72
- klass.new(app, *build_args, &block)
73
- else
74
- klass.new(app, *build_args)
75
- end
33
+ klass.new(app, *args, &block)
76
34
  end
77
35
 
78
- private
79
- def lazy_compare?(object)
80
- object.is_a?(String) || object.is_a?(Symbol)
81
- end
82
-
83
- def normalize(object)
84
- object.to_s.strip.sub(/^::/, '')
85
- end
36
+ private
86
37
 
87
- def build_args
88
- Array(args).map { |arg| arg.respond_to?(:call) ? arg.call : arg }
89
- end
38
+ def normalize(object)
39
+ object.to_s.strip.sub(/^::/, '')
40
+ end
90
41
  end
91
42
 
92
43
  def initialize(*args, &block)
@@ -96,7 +47,7 @@ module ActionDispatch
96
47
 
97
48
  def insert(index, *args, &block)
98
49
  index = self.index(index) unless index.is_a?(Integer)
99
- middleware = Middleware.new(*args, &block)
50
+ middleware = self.class::Middleware.new(*args, &block)
100
51
  super(index, middleware)
101
52
  end
102
53
 
@@ -114,20 +65,19 @@ module ActionDispatch
114
65
  end
115
66
 
116
67
  def use(*args, &block)
117
- middleware = Middleware.new(*args, &block)
68
+ middleware = self.class::Middleware.new(*args, &block)
118
69
  push(middleware)
119
70
  end
120
71
 
121
72
  def active
122
- find_all { |middleware| middleware.active? }
73
+ ActiveSupport::Deprecation.warn "All middlewares in the chaing are active since the laziness " <<
74
+ "was removed from the middleware stack", caller
123
75
  end
124
76
 
125
- def build(app = nil, &blk)
126
- app ||= blk
127
-
77
+ def build(app = nil, &block)
78
+ app ||= block
128
79
  raise "MiddlewareStack#build requires an app" unless app
129
-
130
- active.reverse.inject(app) { |a, e| e.build(a) }
80
+ reverse.inject(app) { |a, e| e.build(a) }
131
81
  end
132
82
  end
133
83
  end
@@ -13,7 +13,7 @@
13
13
  request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
14
14
 
15
15
  def debug_hash(hash)
16
- hash.sort_by { |k, v| k.to_s }.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
16
+ hash.sort_by { |k, v| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
17
17
  end
18
18
  %>
19
19
 
@@ -10,8 +10,6 @@ module ActionDispatch
10
10
 
11
11
  # Prepare dispatcher callbacks and run 'prepare' callbacks
12
12
  initializer "action_dispatch.prepare_dispatcher" do |app|
13
- # TODO: This used to say unless defined?(Dispatcher). Find out why and fix.
14
- require 'rails/dispatcher'
15
13
  ActionDispatch::Callbacks.to_prepare { app.routes_reloader.reload_if_changed }
16
14
  end
17
15
  end
@@ -1,4 +1,5 @@
1
1
  require 'active_support/core_ext/object/blank'
2
+ require 'active_support/core_ext/object/with_options'
2
3
 
3
4
  module ActionDispatch
4
5
  module Routing
@@ -64,10 +64,11 @@ module ActionDispatch
64
64
  end
65
65
 
66
66
  path = normalize_path(path)
67
+ path_without_format = path.sub(/\(\.:format\)$/, '')
67
68
 
68
- if using_match_shorthand?(path, options)
69
- options[:to] ||= path[1..-1].sub(%r{/([^/]*)$}, '#\1')
70
- options[:as] ||= path[1..-1].gsub("/", "_")
69
+ if using_match_shorthand?(path_without_format, options)
70
+ options[:to] ||= path_without_format[1..-1].sub(%r{/([^/]*)$}, '#\1')
71
+ options[:as] ||= path_without_format[1..-1].gsub("/", "_")
71
72
  end
72
73
 
73
74
  [ path, options ]
@@ -462,6 +463,10 @@ module ActionDispatch
462
463
  name.to_s.singularize
463
464
  end
464
465
 
466
+ def member_prefix
467
+ ':id'
468
+ end
469
+
465
470
  def member_name
466
471
  singular
467
472
  end
@@ -508,6 +513,10 @@ module ActionDispatch
508
513
  end
509
514
  end
510
515
 
516
+ def nested_prefix
517
+ id_segment
518
+ end
519
+
511
520
  def nested_options
512
521
  options = { :name_prefix => member_name }
513
522
  options["#{singular}_id".to_sym] = id_constraint if id_constraint?
@@ -531,9 +540,21 @@ module ActionDispatch
531
540
  end
532
541
  end
533
542
 
543
+ def member_prefix
544
+ ''
545
+ end
546
+
534
547
  def member_name
535
548
  name
536
549
  end
550
+
551
+ def nested_prefix
552
+ ''
553
+ end
554
+
555
+ def nested_options
556
+ { :name_prefix => member_name }
557
+ end
537
558
  end
538
559
 
539
560
  def initialize(*args) #:nodoc:
@@ -543,6 +564,7 @@ module ActionDispatch
543
564
 
544
565
  def resource(*resources, &block)
545
566
  options = resources.extract_options!
567
+ options = (@scope[:options] || {}).merge(options)
546
568
 
547
569
  if apply_common_behavior_for(:resource, resources, options, &block)
548
570
  return self
@@ -553,17 +575,17 @@ module ActionDispatch
553
575
  scope(:path => resource.path, :controller => resource.controller) do
554
576
  with_scope_level(:resource, resource) do
555
577
 
556
- scope(:name_prefix => resource.name.to_s, :as => "") do
557
- yield if block_given?
558
- end
578
+ yield if block_given?
559
579
 
560
- scope(resource.options) do
561
- get :show if resource.actions.include?(:show)
562
- post :create if resource.actions.include?(:create)
563
- put :update if resource.actions.include?(:update)
564
- delete :destroy if resource.actions.include?(:destroy)
565
- get :new, :as => resource.name if resource.actions.include?(:new)
566
- get :edit, :as => resource.name if resource.actions.include?(:edit)
580
+ with_scope_level(:member) do
581
+ scope(resource.options) do
582
+ get :show if resource.actions.include?(:show)
583
+ post :create if resource.actions.include?(:create)
584
+ put :update if resource.actions.include?(:update)
585
+ delete :destroy if resource.actions.include?(:destroy)
586
+ get :new, :as => resource.name if resource.actions.include?(:new)
587
+ get :edit, :as => resource.name if resource.actions.include?(:edit)
588
+ end
567
589
  end
568
590
  end
569
591
  end
@@ -573,6 +595,7 @@ module ActionDispatch
573
595
 
574
596
  def resources(*resources, &block)
575
597
  options = resources.extract_options!
598
+ options = (@scope[:options] || {}).merge(options)
576
599
 
577
600
  if apply_common_behavior_for(:resources, resources, options, &block)
578
601
  return self
@@ -621,29 +644,49 @@ module ActionDispatch
621
644
  end
622
645
 
623
646
  def member
624
- unless @scope[:scope_level] == :resources
625
- raise ArgumentError, "can't use member outside resources scope"
647
+ unless resource_scope?
648
+ raise ArgumentError, "can't use member outside resource(s) scope"
626
649
  end
627
650
 
628
651
  with_scope_level(:member) do
629
- scope(':id', :name_prefix => parent_resource.member_name, :as => "") do
652
+ scope(parent_resource.member_prefix, :name_prefix => parent_resource.member_name, :as => "") do
653
+ yield
654
+ end
655
+ end
656
+ end
657
+
658
+ def new
659
+ unless resource_scope?
660
+ raise ArgumentError, "can't use new outside resource(s) scope"
661
+ end
662
+
663
+ with_scope_level(:new) do
664
+ scope(new_scope_prefix, :name_prefix => parent_resource.member_name, :as => "") do
630
665
  yield
631
666
  end
632
667
  end
633
668
  end
634
669
 
635
670
  def nested
636
- unless @scope[:scope_level] == :resources
637
- raise ArgumentError, "can't use nested outside resources scope"
671
+ unless resource_scope?
672
+ raise ArgumentError, "can't use nested outside resource(s) scope"
638
673
  end
639
674
 
640
675
  with_scope_level(:nested) do
641
- scope(parent_resource.id_segment, parent_resource.nested_options) do
676
+ scope(parent_resource.nested_prefix, parent_resource.nested_options) do
642
677
  yield
643
678
  end
644
679
  end
645
680
  end
646
681
 
682
+ def namespace(path)
683
+ if resource_scope?
684
+ nested { super }
685
+ else
686
+ super
687
+ end
688
+ end
689
+
647
690
  def match(*args)
648
691
  options = args.extract_options!
649
692
 
@@ -670,7 +713,7 @@ module ActionDispatch
670
713
  @scope[:path] = old_path
671
714
  end
672
715
  else
673
- with_exclusive_name_prefix(action) do
716
+ with_exclusive_name_prefix(action_name_prefix(action, options)) do
674
717
  return match("#{action_path(action, path_names)}(.:format)", options.reverse_merge(:to => action))
675
718
  end
676
719
  end
@@ -683,15 +726,26 @@ module ActionDispatch
683
726
  return collection { match(*args) }
684
727
  when :member
685
728
  return member { match(*args) }
729
+ when :new
730
+ return new { match(*args) }
686
731
  end
687
732
 
688
- if @scope[:scope_level] == :resources
689
- raise ArgumentError, "can't define route directly in resources scope"
733
+ if @scope[:scope_level] == :resource
734
+ return member { match(*args) }
735
+ end
736
+
737
+ if resource_scope?
738
+ raise ArgumentError, "can't define route directly in resource(s) scope"
690
739
  end
691
740
 
692
741
  super
693
742
  end
694
743
 
744
+ def root(options={})
745
+ options[:on] ||= :collection if @scope[:scope_level] == :resources
746
+ super(options)
747
+ end
748
+
695
749
  protected
696
750
  def parent_resource #:nodoc:
697
751
  @scope[:scope_level_resource]
@@ -703,6 +757,10 @@ module ActionDispatch
703
757
  path_names[name.to_sym] || name.to_s
704
758
  end
705
759
 
760
+ def action_name_prefix(action, options = {})
761
+ (options[:on] == :new || @scope[:scope_level] == :new) ? "#{action}_new" : action
762
+ end
763
+
706
764
  def apply_common_behavior_for(method, resources, options, &block)
707
765
  if resources.length > 1
708
766
  resources.each { |r| send(method, r, options, &block) }
@@ -716,7 +774,7 @@ module ActionDispatch
716
774
  return true
717
775
  end
718
776
 
719
- if @scope[:scope_level] == :resources
777
+ if resource_scope?
720
778
  nested do
721
779
  send(method, resources.pop, options, &block)
722
780
  end
@@ -726,6 +784,14 @@ module ActionDispatch
726
784
  false
727
785
  end
728
786
 
787
+ def new_scope_prefix
788
+ @scope[:path_names][:new] || 'new'
789
+ end
790
+
791
+ def resource_scope?
792
+ [:resource, :resources].include?(@scope[:scope_level])
793
+ end
794
+
729
795
  def with_exclusive_name_prefix(prefix)
730
796
  begin
731
797
  old_name_prefix = @scope[:name_prefix]