actionpack 3.0.0.beta → 3.0.0.beta2

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 (118) hide show
  1. data/CHANGELOG +291 -260
  2. data/lib/abstract_controller.rb +5 -2
  3. data/lib/abstract_controller/assigns.rb +21 -0
  4. data/lib/abstract_controller/base.rb +13 -5
  5. data/lib/abstract_controller/collector.rb +2 -0
  6. data/lib/abstract_controller/helpers.rb +4 -14
  7. data/lib/abstract_controller/layouts.rb +50 -99
  8. data/lib/abstract_controller/logger.rb +2 -2
  9. data/lib/abstract_controller/rendering.rb +105 -173
  10. data/lib/abstract_controller/view_paths.rb +69 -0
  11. data/lib/action_controller.rb +1 -2
  12. data/lib/action_controller/base.rb +10 -32
  13. data/lib/action_controller/caching.rb +19 -18
  14. data/lib/action_controller/caching/actions.rb +17 -11
  15. data/lib/action_controller/caching/fragments.rb +5 -17
  16. data/lib/action_controller/caching/pages.rb +24 -24
  17. data/lib/action_controller/caching/sweeping.rb +1 -3
  18. data/lib/action_controller/deprecated.rb +0 -2
  19. data/lib/action_controller/deprecated/base.rb +143 -0
  20. data/lib/action_controller/metal.rb +29 -26
  21. data/lib/action_controller/metal/compatibility.rb +18 -87
  22. data/lib/action_controller/metal/cookies.rb +0 -1
  23. data/lib/action_controller/metal/head.rb +1 -0
  24. data/lib/action_controller/metal/helpers.rb +2 -2
  25. data/lib/action_controller/metal/hide_actions.rb +4 -6
  26. data/lib/action_controller/metal/http_authentication.rb +18 -33
  27. data/lib/action_controller/metal/implicit_render.rb +21 -0
  28. data/lib/action_controller/metal/instrumentation.rb +1 -1
  29. data/lib/action_controller/metal/mime_responds.rb +2 -1
  30. data/lib/action_controller/metal/rack_delegation.rb +3 -8
  31. data/lib/action_controller/metal/redirecting.rb +2 -1
  32. data/lib/action_controller/metal/renderers.rb +4 -2
  33. data/lib/action_controller/metal/rendering.rb +31 -44
  34. data/lib/action_controller/metal/request_forgery_protection.rb +41 -4
  35. data/lib/action_controller/metal/responder.rb +2 -0
  36. data/lib/action_controller/metal/session_management.rb +0 -36
  37. data/lib/action_controller/metal/streaming.rb +20 -47
  38. data/lib/action_controller/metal/testing.rb +0 -1
  39. data/lib/action_controller/metal/url_for.rb +11 -148
  40. data/lib/action_controller/middleware.rb +2 -1
  41. data/lib/action_controller/polymorphic_routes.rb +1 -2
  42. data/lib/action_controller/railtie.rb +63 -10
  43. data/lib/action_controller/railties/{subscriber.rb → log_subscriber.rb} +5 -12
  44. data/lib/action_controller/railties/url_helpers.rb +14 -0
  45. data/lib/action_controller/record_identifier.rb +20 -1
  46. data/lib/action_controller/test_case.rb +123 -12
  47. data/lib/action_dispatch.rb +1 -0
  48. data/lib/action_dispatch/http/cache.rb +20 -3
  49. data/lib/action_dispatch/http/filter_parameters.rb +40 -25
  50. data/lib/action_dispatch/http/mime_negotiation.rb +6 -17
  51. data/lib/action_dispatch/http/mime_type.rb +2 -7
  52. data/lib/action_dispatch/http/request.rb +12 -33
  53. data/lib/action_dispatch/http/response.rb +35 -15
  54. data/lib/action_dispatch/http/upload.rb +2 -0
  55. data/lib/action_dispatch/http/url.rb +5 -32
  56. data/lib/action_dispatch/middleware/callbacks.rb +1 -1
  57. data/lib/action_dispatch/middleware/cookies.rb +4 -3
  58. data/lib/action_dispatch/middleware/params_parser.rb +4 -3
  59. data/lib/action_dispatch/middleware/remote_ip.rb +51 -0
  60. data/lib/action_dispatch/middleware/session/abstract_store.rb +1 -0
  61. data/lib/action_dispatch/middleware/session/cookie_store.rb +6 -8
  62. data/lib/action_dispatch/middleware/show_exceptions.rb +0 -14
  63. data/lib/action_dispatch/middleware/stack.rb +6 -2
  64. data/lib/action_dispatch/railtie.rb +3 -1
  65. data/lib/action_dispatch/routing.rb +2 -0
  66. data/lib/action_dispatch/routing/deprecated_mapper.rb +35 -7
  67. data/lib/action_dispatch/routing/mapper.rb +134 -48
  68. data/lib/action_dispatch/routing/route.rb +2 -2
  69. data/lib/action_dispatch/routing/route_set.rb +217 -158
  70. data/lib/action_dispatch/routing/url_for.rb +139 -0
  71. data/lib/action_dispatch/testing/assertions/response.rb +14 -61
  72. data/lib/action_dispatch/testing/assertions/routing.rb +25 -14
  73. data/lib/action_dispatch/testing/integration.rb +32 -50
  74. data/lib/action_dispatch/testing/performance_test.rb +3 -1
  75. data/lib/action_dispatch/testing/test_process.rb +2 -0
  76. data/lib/action_dispatch/testing/test_request.rb +2 -0
  77. data/lib/action_pack/version.rb +4 -3
  78. data/lib/action_view.rb +11 -6
  79. data/lib/action_view/base.rb +33 -121
  80. data/lib/action_view/context.rb +0 -2
  81. data/lib/action_view/helpers.rb +26 -23
  82. data/lib/action_view/helpers/active_model_helper.rb +28 -18
  83. data/lib/action_view/helpers/asset_tag_helper.rb +109 -54
  84. data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
  85. data/lib/action_view/helpers/cache_helper.rb +22 -1
  86. data/lib/action_view/helpers/capture_helper.rb +22 -22
  87. data/lib/action_view/helpers/date_helper.rb +6 -5
  88. data/lib/action_view/helpers/form_helper.rb +78 -63
  89. data/lib/action_view/helpers/form_options_helper.rb +6 -4
  90. data/lib/action_view/helpers/form_tag_helper.rb +26 -15
  91. data/lib/action_view/helpers/javascript_helper.rb +90 -10
  92. data/lib/action_view/helpers/number_helper.rb +315 -118
  93. data/lib/action_view/helpers/prototype_helper.rb +19 -46
  94. data/lib/action_view/helpers/record_tag_helper.rb +4 -4
  95. data/lib/action_view/helpers/tag_helper.rb +7 -24
  96. data/lib/action_view/helpers/text_helper.rb +8 -7
  97. data/lib/action_view/helpers/translation_helper.rb +7 -5
  98. data/lib/action_view/helpers/url_helper.rb +19 -16
  99. data/lib/action_view/locale/en.yml +45 -6
  100. data/lib/action_view/lookup_context.rb +190 -0
  101. data/lib/action_view/paths.rb +22 -63
  102. data/lib/action_view/railtie.rb +14 -4
  103. data/lib/action_view/railties/{subscriber.rb → log_subscriber.rb} +1 -1
  104. data/lib/action_view/render/layouts.rb +73 -0
  105. data/lib/action_view/render/partials.rb +15 -41
  106. data/lib/action_view/render/rendering.rb +27 -78
  107. data/lib/action_view/template.rb +20 -24
  108. data/lib/action_view/template/error.rb +22 -2
  109. data/lib/action_view/template/handlers/erb.rb +33 -9
  110. data/lib/action_view/template/handlers/rjs.rb +1 -2
  111. data/lib/action_view/template/resolver.rb +46 -104
  112. data/lib/action_view/template/text.rb +5 -12
  113. data/lib/action_view/test_case.rb +14 -23
  114. metadata +83 -40
  115. data/lib/abstract_controller/compatibility.rb +0 -18
  116. data/lib/abstract_controller/localized_cache.rb +0 -49
  117. data/lib/action_controller/metal/configuration.rb +0 -28
  118. data/lib/action_controller/url_rewriter.rb +0 -76
@@ -6,7 +6,8 @@ module ActionController
6
6
  end
7
7
 
8
8
  def call(env)
9
- @controller.build(@app).dispatch(:index, env)
9
+ request = ActionDispatch::Request.new(env)
10
+ @controller.build(@app).dispatch(:index, request)
10
11
  end
11
12
  end
12
13
 
@@ -92,8 +92,7 @@ module ActionController
92
92
  inflection = if options[:action].to_s == "new"
93
93
  args.pop
94
94
  :singular
95
- elsif (record.respond_to?(:new_record?) && record.new_record?) ||
96
- (record.respond_to?(:destroyed?) && record.destroyed?)
95
+ elsif (record.respond_to?(:persisted?) && !record.persisted?)
97
96
  args.pop
98
97
  :plural
99
98
  elsif record.is_a?(Class)
@@ -1,30 +1,83 @@
1
- require "action_controller"
2
1
  require "rails"
2
+ require "action_controller"
3
+ require "action_dispatch/railtie"
3
4
  require "action_view/railtie"
5
+ require "active_support/core_ext/class/subclasses"
6
+ require "active_support/deprecation/proxy_wrappers"
7
+ require "active_support/deprecation"
8
+
9
+ require "action_controller/railties/log_subscriber"
10
+ require "action_controller/railties/url_helpers"
4
11
 
5
12
  module ActionController
6
13
  class Railtie < Rails::Railtie
7
- railtie_name :action_controller
14
+ config.action_controller = ActiveSupport::OrderedOptions.new
15
+
16
+ ad = config.action_dispatch
17
+ config.action_controller.singleton_class.send(:define_method, :session) do
18
+ ActiveSupport::Deprecation.warn "config.action_controller.session has been " \
19
+ "renamed to config.action_dispatch.session.", caller
20
+ ad.session
21
+ end
8
22
 
9
- require "action_controller/railties/subscriber"
10
- subscriber ActionController::Railties::Subscriber.new
23
+ config.action_controller.singleton_class.send(:define_method, :session=) do |val|
24
+ ActiveSupport::Deprecation.warn "config.action_controller.session has been " \
25
+ "renamed to config.action_dispatch.session.", caller
26
+ ad.session = val
27
+ end
28
+
29
+ config.action_controller.singleton_class.send(:define_method, :session_store) do
30
+ ActiveSupport::Deprecation.warn "config.action_controller.session_store has been " \
31
+ "renamed to config.action_dispatch.session_store.", caller
32
+ ad.session_store
33
+ end
34
+
35
+ config.action_controller.singleton_class.send(:define_method, :session_store=) do |val|
36
+ ActiveSupport::Deprecation.warn "config.action_controller.session_store has been " \
37
+ "renamed to config.action_dispatch.session_store.", caller
38
+ ad.session_store = val
39
+ end
40
+
41
+ log_subscriber :action_controller, ActionController::Railties::LogSubscriber.new
11
42
 
12
43
  initializer "action_controller.logger" do
13
- ActionController::Base.logger ||= Rails.logger
44
+ ActiveSupport.on_load(:action_controller) { self.logger ||= Rails.logger }
14
45
  end
15
46
 
16
47
  initializer "action_controller.set_configs" do |app|
17
- app.config.action_controller.each do |k,v|
18
- ActionController::Base.send "#{k}=", v
48
+ paths = app.config.paths
49
+ ac = app.config.action_controller
50
+
51
+ ac.assets_dir = paths.public.to_a.first
52
+ ac.javascripts_dir = paths.public.javascripts.to_a.first
53
+ ac.stylesheets_dir = paths.public.stylesheets.to_a.first
54
+ ac.secret = app.config.cookie_secret
55
+
56
+ ActiveSupport.on_load(:action_controller) do
57
+ self.config.merge!(ac)
19
58
  end
20
59
  end
21
60
 
22
61
  initializer "action_controller.initialize_framework_caches" do
23
- ActionController::Base.cache_store ||= RAILS_CACHE
62
+ ActiveSupport.on_load(:action_controller) { self.cache_store ||= RAILS_CACHE }
24
63
  end
25
64
 
26
65
  initializer "action_controller.set_helpers_path" do |app|
27
- ActionController::Base.helpers_path = app.config.paths.app.helpers.to_a
66
+ ActiveSupport.on_load(:action_controller) do
67
+ self.helpers_path = app.config.paths.app.helpers.to_a
68
+ end
69
+ end
70
+
71
+ initializer "action_controller.url_helpers" do |app|
72
+ ActiveSupport.on_load(:action_controller) do
73
+ extend ::ActionController::Railties::UrlHelpers.with(app.routes)
74
+ end
75
+
76
+ message = "ActionController::Routing::Routes is deprecated. " \
77
+ "Instead, use Rails.application.routes"
78
+
79
+ proxy = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(app.routes, message)
80
+ ActionController::Routing::Routes = proxy
28
81
  end
29
82
  end
30
- end
83
+ end
@@ -1,6 +1,8 @@
1
+ require 'active_support/core_ext/object/blank'
2
+
1
3
  module ActionController
2
4
  module Railties
3
- class Subscriber < Rails::Subscriber
5
+ class LogSubscriber < Rails::LogSubscriber
4
6
  INTERNAL_PARAMS = %w(controller action format _method only_path)
5
7
 
6
8
  def start_processing(event)
@@ -15,23 +17,14 @@ module ActionController
15
17
  payload = event.payload
16
18
  additions = ActionController::Base.log_process_action(payload)
17
19
 
18
- message = "Completed in %.0fms" % event.duration
20
+ message = "Completed #{payload[:status]} #{Rack::Utils::HTTP_STATUS_CODES[payload[:status]]} in %.0fms" % event.duration
19
21
  message << " (#{additions.join(" | ")})" unless additions.blank?
20
- message << " with #{payload[:status]}"
21
22
 
22
23
  info(message)
23
24
  end
24
25
 
25
26
  def send_file(event)
26
- message = if event.payload[:x_sendfile]
27
- header = ActionController::Streaming::X_SENDFILE_HEADER
28
- "Sent #{header} header %s"
29
- elsif event.payload[:stream]
30
- "Streamed file %s"
31
- else
32
- "Sent file %s"
33
- end
34
-
27
+ message = "Sent file %s"
35
28
  message << " (%.1fms)"
36
29
  info(message % [event.payload[:path], event.duration])
37
30
  end
@@ -0,0 +1,14 @@
1
+ module ActionController
2
+ module Railties
3
+ module UrlHelpers
4
+ def self.with(routes)
5
+ Module.new do
6
+ define_method(:inherited) do |klass|
7
+ super(klass)
8
+ klass.send(:include, routes.url_helpers)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -60,13 +60,32 @@ module ActionController
60
60
  #
61
61
  # dom_id(Post.find(45), :edit) # => "edit_post_45"
62
62
  def dom_id(record, prefix = nil)
63
- if record_id = record.id
63
+ if record_id = record_key_for_dom_id(record)
64
64
  "#{dom_class(record, prefix)}#{JOIN}#{record_id}"
65
65
  else
66
66
  dom_class(record, prefix || NEW)
67
67
  end
68
68
  end
69
69
 
70
+ # Returns a string representation of the key attribute(s) that is suitable for use in an HTML DOM id.
71
+ # This can be overwritten to customize the default generated string representation if desired.
72
+ # If you need to read back a key from a dom_id in order to query for the underlying database record,
73
+ # you should write a helper like 'person_record_from_dom_id' that will extract the key either based
74
+ # on the default implementation (which just joins all key attributes with '-') or on your own
75
+ # overwritten version of the method. By default, this implementation passes the key string through a
76
+ # method that replaces all characters that are invalid inside DOM ids, with valid ones. You need to
77
+ # make sure yourself that your dom ids are valid, in case you overwrite this method.
78
+ def record_key_for_dom_id(record)
79
+ record = record.to_model if record.respond_to?(:to_model)
80
+ key = record.to_key
81
+ key ? sanitize_dom_id(key.join('_')) : key
82
+ end
83
+
84
+ # Replaces characters that are invalid in HTML DOM ids with valid ones.
85
+ def sanitize_dom_id(candidate_id)
86
+ candidate_id # TODO implement conversion to valid DOM id values
87
+ end
88
+
70
89
  # Returns the plural class name of a record or class. Examples:
71
90
  #
72
91
  # plural_class_name(post) # => "posts"
@@ -1,7 +1,108 @@
1
1
  require 'rack/session/abstract/id'
2
- require 'action_view/test_case'
2
+ require 'active_support/core_ext/object/blank'
3
3
 
4
4
  module ActionController
5
+ module TemplateAssertions
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ setup :setup_subscriptions
10
+ teardown :teardown_subscriptions
11
+ end
12
+
13
+ def setup_subscriptions
14
+ @partials = Hash.new(0)
15
+ @templates = Hash.new(0)
16
+ @layouts = Hash.new(0)
17
+
18
+ ActiveSupport::Notifications.subscribe("action_view.render_template") do |name, start, finish, id, payload|
19
+ path = payload[:layout]
20
+ @layouts[path] += 1
21
+ end
22
+
23
+ ActiveSupport::Notifications.subscribe("action_view.render_template!") do |name, start, finish, id, payload|
24
+ path = payload[:virtual_path]
25
+ next unless path
26
+ partial = path =~ /^.*\/_[^\/]*$/
27
+ if partial
28
+ @partials[path] += 1
29
+ @partials[path.split("/").last] += 1
30
+ @templates[path] += 1
31
+ else
32
+ @templates[path] += 1
33
+ end
34
+ end
35
+ end
36
+
37
+ def teardown_subscriptions
38
+ ActiveSupport::Notifications.unsubscribe("action_view.render_template!")
39
+ end
40
+
41
+ # Asserts that the request was rendered with the appropriate template file or partials
42
+ #
43
+ # ==== Examples
44
+ #
45
+ # # assert that the "new" view template was rendered
46
+ # assert_template "new"
47
+ #
48
+ # # assert that the "_customer" partial was rendered twice
49
+ # assert_template :partial => '_customer', :count => 2
50
+ #
51
+ # # assert that no partials were rendered
52
+ # assert_template :partial => false
53
+ #
54
+ def assert_template(options = {}, message = nil)
55
+ validate_request!
56
+
57
+ case options
58
+ when NilClass, String
59
+ rendered = @templates
60
+ msg = build_message(message,
61
+ "expecting <?> but rendering with <?>",
62
+ options, rendered.keys.join(', '))
63
+ assert_block(msg) do
64
+ if options.nil?
65
+ @templates.blank?
66
+ else
67
+ rendered.any? { |t,num| t.match(options) }
68
+ end
69
+ end
70
+ when Hash
71
+ if expected_partial = options[:partial]
72
+ if expected_count = options[:count]
73
+ actual_count = @partials[expected_partial]
74
+ # actual_count = found.nil? ? 0 : found[1]
75
+ msg = build_message(message,
76
+ "expecting ? to be rendered ? time(s) but rendered ? time(s)",
77
+ expected_partial, expected_count, actual_count)
78
+ assert(actual_count == expected_count.to_i, msg)
79
+ elsif options.key?(:layout)
80
+ msg = build_message(message,
81
+ "expecting layout <?> but action rendered <?>",
82
+ expected_layout, @layouts.keys)
83
+
84
+ case layout = options[:layout]
85
+ when String
86
+ assert(@layouts.include?(expected_layout), msg)
87
+ when Regexp
88
+ assert(@layouts.any? {|l| l =~ layout }, msg)
89
+ when nil
90
+ assert(@layouts.empty?, msg)
91
+ end
92
+ else
93
+ msg = build_message(message,
94
+ "expecting partial <?> but action rendered <?>",
95
+ options[:partial], @partials.keys)
96
+ assert(@partials.include?(expected_partial), msg)
97
+ end
98
+ else
99
+ assert @partials.empty?,
100
+ "Expected no partials to be rendered"
101
+ end
102
+ end
103
+ end
104
+ end
105
+
5
106
  class TestRequest < ActionDispatch::TestRequest #:nodoc:
6
107
  def initialize(env = {})
7
108
  super
@@ -17,9 +118,9 @@ module ActionController
17
118
  end
18
119
  end
19
120
 
20
- def assign_parameters(controller_path, action, parameters = {})
121
+ def assign_parameters(routes, controller_path, action, parameters = {})
21
122
  parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action)
22
- extra_keys = ActionController::Routing::Routes.extra_keys(parameters)
123
+ extra_keys = routes.extra_keys(parameters)
23
124
  non_path_parameters = get? ? query_parameters : request_parameters
24
125
  parameters.each do |key, value|
25
126
  if value.is_a? Fixnum
@@ -181,6 +282,7 @@ module ActionController
181
282
  # assert_redirected_to page_url(:title => 'foo')
182
283
  class TestCase < ActiveSupport::TestCase
183
284
  include ActionDispatch::TestProcess
285
+ include ActionController::TemplateAssertions
184
286
 
185
287
  # Executes a request simulating GET HTTP method and set/volley the response
186
288
  def get(action, parameters = nil, session = nil, flash = nil)
@@ -220,7 +322,7 @@ module ActionController
220
322
  def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
221
323
  # Sanity check for required instance variables so we can give an
222
324
  # understandable error message.
223
- %w(@controller @request @response).each do |iv_name|
325
+ %w(@routes @controller @request @response).each do |iv_name|
224
326
  if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
225
327
  raise "#{iv_name} is nil: make sure you set it in your test's setup method."
226
328
  end
@@ -236,7 +338,7 @@ module ActionController
236
338
  @request.env['REQUEST_METHOD'] = http_method
237
339
 
238
340
  parameters ||= {}
239
- @request.assign_parameters(@controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
341
+ @request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
240
342
 
241
343
  @request.session = ActionController::TestSession.new(session) unless session.nil?
242
344
  @request.session["flash"] = @request.flash.update(flash || {})
@@ -322,6 +424,8 @@ module ActionController
322
424
  @controller ||= klass.new rescue nil
323
425
  end
324
426
 
427
+ @request.env.delete('PATH_INFO')
428
+
325
429
  if @controller
326
430
  @controller.request = @request
327
431
  @controller.params = {}
@@ -335,13 +439,20 @@ module ActionController
335
439
 
336
440
  private
337
441
  def build_request_uri(action, parameters)
338
- unless @request.env['REQUEST_URI']
339
- options = @controller.__send__(:rewrite_options, parameters)
340
- options.update(:only_path => true, :action => action)
341
-
342
- url = ActionController::UrlRewriter.new(@request, parameters)
343
- @request.request_uri = url.rewrite(options)
442
+ unless @request.env["PATH_INFO"]
443
+ options = @controller.__send__(:url_options).merge(parameters)
444
+ options.update(
445
+ :only_path => true,
446
+ :action => action,
447
+ :relative_url_root => nil,
448
+ :_path_segments => @request.symbolized_path_parameters)
449
+
450
+ url, query_string = @routes.url_for(options).split("?", 2)
451
+
452
+ @request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
453
+ @request.env["PATH_INFO"] = url
454
+ @request.env["QUERY_STRING"] = query_string || ""
344
455
  end
345
456
  end
346
- end
457
+ end
347
458
  end
@@ -48,6 +48,7 @@ module ActionDispatch
48
48
  autoload :Flash
49
49
  autoload :Head
50
50
  autoload :ParamsParser
51
+ autoload :RemoteIp
51
52
  autoload :Rescue
52
53
  autoload :ShowExceptions
53
54
  autoload :Static
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/object/blank'
2
+
1
3
  module ActionDispatch
2
4
  module Http
3
5
  module Cache
@@ -37,8 +39,21 @@ module ActionDispatch
37
39
  end
38
40
 
39
41
  module Response
40
- def cache_control
41
- @cache_control ||= {}
42
+ attr_reader :cache_control
43
+
44
+ def initialize(*)
45
+ status, header, body = super
46
+
47
+ @cache_control = {}
48
+ @etag = self["ETag"]
49
+
50
+ if cache_control = self["Cache-Control"]
51
+ cache_control.split(/,\s*/).each do |segment|
52
+ first, last = segment.split("=")
53
+ last ||= true
54
+ @cache_control[first.to_sym] = last
55
+ end
56
+ end
42
57
  end
43
58
 
44
59
  def last_modified
@@ -65,7 +80,7 @@ module ActionDispatch
65
80
 
66
81
  def etag=(etag)
67
82
  key = ActiveSupport::Cache.expand_cache_key(etag)
68
- @etag = %("#{Digest::MD5.hexdigest(key)}")
83
+ @etag = self["ETag"] = %("#{Digest::MD5.hexdigest(key)}")
69
84
  end
70
85
 
71
86
  private
@@ -100,6 +115,8 @@ module ActionDispatch
100
115
  def set_conditional_cache_control!
101
116
  control = @cache_control
102
117
 
118
+ return if self["Cache-Control"].present?
119
+
103
120
  if control.empty?
104
121
  headers["Cache-Control"] = DEFAULT_CACHE_CONTROL
105
122
  elsif @cache_control[:no_cache]
@@ -1,5 +1,6 @@
1
1
  require 'active_support/core_ext/object/blank'
2
2
  require 'active_support/core_ext/hash/keys'
3
+ require 'active_support/core_ext/object/duplicable'
3
4
 
4
5
  module ActionDispatch
5
6
  module Http
@@ -25,9 +26,15 @@ module ActionDispatch
25
26
  module FilterParameters
26
27
  extend ActiveSupport::Concern
27
28
 
29
+ @@compiled_parameter_filter_for = {}
30
+
28
31
  # Return a hash of parameters with all sensitive data replaced.
29
32
  def filtered_parameters
30
- @filtered_parameters ||= process_parameter_filter(parameters)
33
+ @filtered_parameters ||= if filtering_parameters?
34
+ process_parameter_filter(parameters)
35
+ else
36
+ parameters.dup
37
+ end
31
38
  end
32
39
  alias :fitered_params :filtered_parameters
33
40
 
@@ -46,10 +53,18 @@ module ActionDispatch
46
53
 
47
54
  protected
48
55
 
49
- def compile_parameter_filter #:nodoc:
56
+ def filtering_parameters? #:nodoc:
57
+ @env["action_dispatch.parameter_filter"].present?
58
+ end
59
+
60
+ def process_parameter_filter(params) #:nodoc:
61
+ compiled_parameter_filter_for(@env["action_dispatch.parameter_filter"]).call(params)
62
+ end
63
+
64
+ def compile_parameter_filter(filters) #:nodoc:
50
65
  strings, regexps, blocks = [], [], []
51
66
 
52
- Array(@env["action_dispatch.parameter_filter"]).each do |item|
67
+ filters.each do |item|
53
68
  case item
54
69
  when NilClass
55
70
  when Proc
@@ -65,34 +80,34 @@ module ActionDispatch
65
80
  [regexps, blocks]
66
81
  end
67
82
 
68
- def filtering_parameters? #:nodoc:
69
- @env["action_dispatch.parameter_filter"].present?
70
- end
83
+ def compiled_parameter_filter_for(filters) #:nodoc:
84
+ @@compiled_parameter_filter_for[filters] ||= begin
85
+ regexps, blocks = compile_parameter_filter(filters)
71
86
 
72
- def process_parameter_filter(original_params) #:nodoc:
73
- return original_params.dup unless filtering_parameters?
87
+ lambda do |original_params|
88
+ filtered_params = {}
74
89
 
75
- filtered_params = {}
76
- regexps, blocks = compile_parameter_filter
90
+ original_params.each do |key, value|
91
+ if regexps.find { |r| key =~ r }
92
+ value = '[FILTERED]'
93
+ elsif value.is_a?(Hash)
94
+ value = process_parameter_filter(value)
95
+ elsif value.is_a?(Array)
96
+ value = value.map { |v| v.is_a?(Hash) ? process_parameter_filter(v) : v }
97
+ elsif blocks.present?
98
+ key = key.dup
99
+ value = value.dup if value.duplicable?
100
+ blocks.each { |b| b.call(key, value) }
101
+ end
77
102
 
78
- original_params.each do |key, value|
79
- if regexps.find { |r| key =~ r }
80
- value = '[FILTERED]'
81
- elsif value.is_a?(Hash)
82
- value = process_parameter_filter(value)
83
- elsif value.is_a?(Array)
84
- value = value.map { |i| process_parameter_filter(i) }
85
- elsif blocks.present?
86
- key = key.dup
87
- value = value.dup if value.duplicable?
88
- blocks.each { |b| b.call(key, value) }
89
- end
103
+ filtered_params[key] = value
104
+ end
90
105
 
91
- filtered_params[key] = value
106
+ filtered_params
107
+ end
92
108
  end
93
-
94
- filtered_params
95
109
  end
110
+
96
111
  end
97
112
  end
98
113
  end