actionpack 1.11.2 → 1.12.0

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 (149) hide show
  1. data/CHANGELOG +392 -5
  2. data/lib/action_controller.rb +8 -4
  3. data/lib/action_controller/assertions.rb +9 -10
  4. data/lib/action_controller/base.rb +177 -88
  5. data/lib/action_controller/benchmarking.rb +5 -5
  6. data/lib/action_controller/caching.rb +44 -36
  7. data/lib/action_controller/cgi_ext/cgi_methods.rb +71 -6
  8. data/lib/action_controller/cgi_ext/cookie_performance_fix.rb +1 -1
  9. data/lib/action_controller/cgi_process.rb +36 -24
  10. data/lib/action_controller/components.rb +152 -52
  11. data/lib/action_controller/dependencies.rb +1 -1
  12. data/lib/action_controller/deprecated_redirects.rb +2 -2
  13. data/lib/action_controller/deprecated_request_methods.rb +34 -0
  14. data/lib/action_controller/filters.rb +59 -19
  15. data/lib/action_controller/flash.rb +53 -47
  16. data/lib/action_controller/helpers.rb +2 -2
  17. data/lib/action_controller/integration.rb +524 -0
  18. data/lib/action_controller/layout.rb +58 -23
  19. data/lib/action_controller/mime_responds.rb +163 -0
  20. data/lib/action_controller/mime_type.rb +142 -0
  21. data/lib/action_controller/pagination.rb +13 -7
  22. data/lib/action_controller/request.rb +59 -56
  23. data/lib/action_controller/rescue.rb +1 -1
  24. data/lib/action_controller/routing.rb +29 -10
  25. data/lib/action_controller/scaffolding.rb +8 -0
  26. data/lib/action_controller/session/active_record_store.rb +21 -10
  27. data/lib/action_controller/session/mem_cache_store.rb +18 -12
  28. data/lib/action_controller/session_management.rb +30 -11
  29. data/lib/action_controller/templates/rescues/_trace.rhtml +1 -1
  30. data/lib/action_controller/templates/scaffolds/layout.rhtml +4 -4
  31. data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
  32. data/lib/action_controller/test_process.rb +189 -118
  33. data/lib/action_controller/vendor/html-scanner/html/node.rb +20 -1
  34. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +3 -0
  35. data/lib/action_controller/vendor/html-scanner/html/version.rb +1 -1
  36. data/lib/action_controller/vendor/xml_node.rb +97 -0
  37. data/lib/action_controller/verification.rb +2 -0
  38. data/lib/action_pack/version.rb +3 -3
  39. data/lib/action_view.rb +0 -2
  40. data/lib/action_view/base.rb +109 -36
  41. data/lib/action_view/compiled_templates.rb +1 -1
  42. data/lib/action_view/helpers/active_record_helper.rb +4 -2
  43. data/lib/action_view/helpers/asset_tag_helper.rb +6 -7
  44. data/lib/action_view/helpers/capture_helper.rb +49 -12
  45. data/lib/action_view/helpers/date_helper.rb +14 -4
  46. data/lib/action_view/helpers/form_helper.rb +136 -20
  47. data/lib/action_view/helpers/form_options_helper.rb +29 -7
  48. data/lib/action_view/helpers/form_tag_helper.rb +22 -20
  49. data/lib/action_view/helpers/java_script_macros_helper.rb +29 -9
  50. data/lib/action_view/helpers/javascript_helper.rb +50 -446
  51. data/lib/action_view/helpers/javascripts/controls.js +95 -30
  52. data/lib/action_view/helpers/javascripts/dragdrop.js +161 -21
  53. data/lib/action_view/helpers/javascripts/effects.js +310 -211
  54. data/lib/action_view/helpers/javascripts/prototype.js +228 -28
  55. data/lib/action_view/helpers/number_helper.rb +9 -9
  56. data/lib/action_view/helpers/pagination_helper.rb +1 -1
  57. data/lib/action_view/helpers/prototype_helper.rb +900 -0
  58. data/lib/action_view/helpers/scriptaculous_helper.rb +135 -0
  59. data/lib/action_view/helpers/text_helper.rb +7 -6
  60. data/lib/action_view/helpers/url_helper.rb +23 -14
  61. data/lib/action_view/partials.rb +12 -4
  62. data/rakefile +13 -5
  63. data/test/abstract_unit.rb +4 -3
  64. data/test/active_record_unit.rb +88 -0
  65. data/test/{controller → activerecord}/active_record_assertions_test.rb +7 -50
  66. data/test/{controller → activerecord}/active_record_store_test.rb +27 -4
  67. data/test/activerecord/pagination_test.rb +161 -0
  68. data/test/controller/action_pack_assertions_test.rb +18 -15
  69. data/test/controller/base_test.rb +31 -42
  70. data/test/controller/benchmark_test.rb +8 -11
  71. data/test/controller/capture_test.rb +33 -1
  72. data/test/controller/cgi_test.rb +33 -0
  73. data/test/controller/custom_handler_test.rb +8 -0
  74. data/test/controller/fake_controllers.rb +9 -17
  75. data/test/controller/filters_test.rb +32 -3
  76. data/test/controller/flash_test.rb +26 -41
  77. data/test/controller/fragment_store_setting_test.rb +1 -1
  78. data/test/controller/layout_test.rb +73 -0
  79. data/test/controller/mime_responds_test.rb +257 -0
  80. data/test/controller/mime_type_test.rb +24 -0
  81. data/test/controller/new_render_test.rb +157 -1
  82. data/test/controller/redirect_test.rb +23 -0
  83. data/test/controller/render_test.rb +54 -56
  84. data/test/controller/request_test.rb +25 -0
  85. data/test/controller/routing_test.rb +74 -66
  86. data/test/controller/test_test.rb +66 -1
  87. data/test/controller/verification_test.rb +3 -1
  88. data/test/controller/webservice_test.rb +255 -0
  89. data/test/fixtures/companies.yml +24 -0
  90. data/test/fixtures/company.rb +9 -0
  91. data/test/fixtures/db_definitions/sqlite.sql +42 -0
  92. data/test/fixtures/developer.rb +7 -0
  93. data/test/fixtures/developers.yml +21 -0
  94. data/test/fixtures/developers_projects.yml +13 -0
  95. data/test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml +1 -0
  96. data/test/fixtures/layout_tests/layouts/item.rhtml +1 -0
  97. data/test/fixtures/layout_tests/layouts/layout_test.rhtml +1 -0
  98. data/test/fixtures/layout_tests/layouts/third_party_template_library.mab +1 -0
  99. data/test/fixtures/layout_tests/views/hello.rhtml +1 -0
  100. data/test/fixtures/multipart/mona_lisa.jpg +0 -0
  101. data/test/fixtures/project.rb +3 -0
  102. data/test/fixtures/projects.yml +7 -0
  103. data/test/fixtures/replies.yml +13 -0
  104. data/test/fixtures/reply.rb +5 -0
  105. data/test/fixtures/respond_to/all_types_with_layout.rhtml +1 -0
  106. data/test/fixtures/respond_to/all_types_with_layout.rjs +1 -0
  107. data/test/fixtures/respond_to/layouts/standard.rhtml +1 -0
  108. data/test/fixtures/respond_to/using_defaults.rhtml +1 -0
  109. data/test/fixtures/respond_to/using_defaults.rjs +1 -0
  110. data/test/fixtures/respond_to/using_defaults.rxml +1 -0
  111. data/test/fixtures/respond_to/using_defaults_with_type_list.rhtml +1 -0
  112. data/test/fixtures/respond_to/using_defaults_with_type_list.rjs +1 -0
  113. data/test/fixtures/respond_to/using_defaults_with_type_list.rxml +1 -0
  114. data/test/fixtures/test/block_content_for.rhtml +2 -0
  115. data/test/fixtures/test/delete_with_js.rjs +2 -0
  116. data/test/fixtures/test/dot.directory/render_file_with_ivar.rhtml +1 -0
  117. data/test/fixtures/test/enum_rjs_test.rjs +6 -0
  118. data/test/fixtures/test/erb_content_for.rhtml +2 -0
  119. data/test/fixtures/test/hello_world.rxml +3 -0
  120. data/test/fixtures/test/hello_world_with_layout_false.rhtml +1 -0
  121. data/test/fixtures/test/non_erb_block_content_for.rxml +4 -0
  122. data/test/fixtures/topic.rb +3 -0
  123. data/test/fixtures/topics.yml +22 -0
  124. data/test/template/active_record_helper_test.rb +4 -0
  125. data/test/template/asset_tag_helper_test.rb +7 -2
  126. data/test/template/date_helper_test.rb +39 -2
  127. data/test/template/form_helper_test.rb +238 -5
  128. data/test/template/form_options_helper_test.rb +78 -0
  129. data/test/template/form_tag_helper_test.rb +11 -0
  130. data/test/template/java_script_macros_helper_test.rb +51 -6
  131. data/test/template/javascript_helper_test.rb +7 -153
  132. data/test/template/number_helper_test.rb +14 -13
  133. data/test/template/prototype_helper_test.rb +423 -0
  134. data/test/template/scriptaculous_helper_test.rb +90 -0
  135. data/test/template/text_helper_test.rb +12 -9
  136. data/test/template/url_helper_test.rb +31 -15
  137. metadata +291 -246
  138. data/lib/action_controller/cgi_ext/multipart_progress.rb +0 -169
  139. data/lib/action_controller/upload_progress.rb +0 -473
  140. data/lib/action_controller/vendor/html-scanner/html/node.rb.rej +0 -17
  141. data/lib/action_view/helpers/upload_progress_helper.rb +0 -433
  142. data/lib/action_view/vendor/builder.rb +0 -13
  143. data/lib/action_view/vendor/builder/blankslate.rb +0 -53
  144. data/lib/action_view/vendor/builder/xmlbase.rb +0 -143
  145. data/lib/action_view/vendor/builder/xmlevents.rb +0 -63
  146. data/lib/action_view/vendor/builder/xmlmarkup.rb +0 -308
  147. data/test/controller/multipart_progress_testx.rb +0 -365
  148. data/test/controller/upload_progress_testx.rb +0 -89
  149. data/test/template/upload_progress_helper_testx.rb +0 -136
@@ -1,18 +1,18 @@
1
1
  module ActionController #:nodoc:
2
- # Components allows you to call other actions for their rendered response while executing another action. You can either delegate
2
+ # Components allow you to call other actions for their rendered response while executing another action. You can either delegate
3
3
  # the entire response rendering or you can mix a partial response in with your other content.
4
4
  #
5
5
  # class WeblogController < ActionController::Base
6
6
  # # Performs a method and then lets hello_world output its render
7
7
  # def delegate_action
8
8
  # do_other_stuff_before_hello_world
9
- # render_component :controller => "greeter", :action => "hello_world", :params => { "person" => "david" }
9
+ # render_component :controller => "greeter", :action => "hello_world", :params => { :person => "david" }
10
10
  # end
11
11
  # end
12
12
  #
13
13
  # class GreeterController < ActionController::Base
14
14
  # def hello_world
15
- # render_text "#{@params['person']} says, Hello World!"
15
+ # render :text => "#{params[:person]} says, Hello World!"
16
16
  # end
17
17
  # end
18
18
  #
@@ -20,67 +20,167 @@ module ActionController #:nodoc:
20
20
  #
21
21
  # Let's see a greeting:
22
22
  # <%= render_component :controller => "greeter", :action => "hello_world" %>
23
+ #
24
+ # It is also possible to specify the controller as a class constant, bypassing the inflector
25
+ # code to compute the controller class at runtime:
26
+ #
27
+ # <%= render_component :controller => GreeterController, :action => "hello_world" %>
28
+ #
29
+ # == When to use components
30
+ #
31
+ # Components should be used with care. They're significantly slower than simply splitting reusable parts into partials and
32
+ # conceptually more complicated. Don't use components as a way of separating concerns inside a single application. Instead,
33
+ # reserve components to those rare cases where you truly have reusable view and controller elements that can be employed
34
+ # across many applications at once.
35
+ #
36
+ # So to repeat: Components are a special-purpose approach that can often be replaced with better use of partials and filters.
23
37
  module Components
24
- def self.append_features(base) #:nodoc:
25
- super
38
+ def self.included(base) #:nodoc:
39
+ base.send :include, InstanceMethods
40
+ base.extend(ClassMethods)
41
+
26
42
  base.helper do
27
43
  def render_component(options)
28
44
  @controller.send(:render_component_as_string, options)
29
45
  end
30
46
  end
31
- end
47
+
48
+ # If this controller was instantiated to process a component request,
49
+ # +parent_controller+ points to the instantiator of this controller.
50
+ base.send :attr_accessor, :parent_controller
51
+
52
+ base.class_eval do
53
+ alias_method :process_cleanup_without_components, :process_cleanup
54
+ alias_method :process_cleanup, :process_cleanup_with_components
55
+
56
+ alias_method :set_session_options_without_components, :set_session_options
57
+ alias_method :set_session_options, :set_session_options_with_components
58
+
59
+ alias_method :flash_without_components, :flash
60
+ alias_method :flash, :flash_with_components
32
61
 
33
- protected
34
- # Renders the component specified as the response for the current method
35
- def render_component(options = {}) #:doc:
36
- component_logging(options) { render_text(component_response(options).body, response.headers["Status"]) }
62
+ alias_method :component_request?, :parent_controller
37
63
  end
64
+ end
38
65
 
39
- # Returns the component response as a string
40
- def render_component_as_string(options) #:doc:
41
- component_logging(options) do
42
- response = component_response(options, false)
43
- unless response.redirected_to.nil?
44
- render_component_as_string response.redirected_to
45
- else
46
- response.body
47
- end
48
- end
66
+ module ClassMethods
67
+ # Track parent controller to identify component requests
68
+ def process_with_components(request, response, parent_controller = nil) #:nodoc:
69
+ controller = new
70
+ controller.parent_controller = parent_controller
71
+ controller.process(request, response)
49
72
  end
50
-
51
- private
52
- def component_response(options, reuse_response = true)
53
- begin
54
- ActionController::Flash::FlashHash.avoid_sweep = true
55
- p = component_class(options).process(request_for_component(options), reuse_response ? @response : response_for_component)
56
- ensure
57
- ActionController::Flash::FlashHash.avoid_sweep = false
58
- end
59
- p
60
- end
61
-
62
- def component_class(options)
63
- options[:controller] ? (options[:controller].camelize + "Controller").constantize : self.class
64
- end
65
-
66
- def request_for_component(options)
67
- request_for_component = @request.dup
68
- request_for_component.send(
69
- :instance_variable_set, :@parameters,
70
- (options[:params] || {}).merge({ "controller" => options[:controller], "action" => options[:action], "id" => options[:id] }).with_indifferent_access
71
- )
72
- return request_for_component
73
+
74
+ # Set the template root to be one directory behind the root dir of the controller. Examples:
75
+ # /code/weblog/components/admin/users_controller.rb with Admin::UsersController
76
+ # will use /code/weblog/components as template root
77
+ # and find templates in /code/weblog/components/admin/users/
78
+ #
79
+ # /code/weblog/components/admin/parties/users_controller.rb with Admin::Parties::UsersController
80
+ # will also use /code/weblog/components as template root
81
+ # and find templates in /code/weblog/components/admin/parties/users/
82
+ def uses_component_template_root
83
+ path_of_calling_controller = File.dirname(caller[0].split(/:\d+:/).first)
84
+ path_of_controller_root = path_of_calling_controller.sub(/#{controller_path.split("/")[0..-2]}$/, "") # " (for ruby-mode)
85
+
86
+ self.template_root = path_of_controller_root
73
87
  end
74
-
75
- def response_for_component
76
- @response.dup
88
+ end
89
+
90
+ module InstanceMethods
91
+ # Extracts the action_name from the request parameters and performs that action.
92
+ def process_with_components(request, response, method = :perform_action, *arguments) #:nodoc:
93
+ flash.discard if component_request?
94
+ process_without_components(request, response, method, *arguments)
77
95
  end
78
96
 
79
- def component_logging(options)
80
- logger.info("Start rendering component (#{options.inspect}): ") unless logger.nil?
81
- result = yield
82
- logger.info("\n\nEnd of component rendering") unless logger.nil?
83
- return result
84
- end
97
+ protected
98
+ # Renders the component specified as the response for the current method
99
+ def render_component(options) #:doc:
100
+ component_logging(options) do
101
+ render_text(component_response(options, true).body, response.headers["Status"])
102
+ end
103
+ end
104
+
105
+ # Returns the component response as a string
106
+ def render_component_as_string(options) #:doc:
107
+ component_logging(options) do
108
+ response = component_response(options, false)
109
+
110
+ if redirected = response.redirected_to
111
+ render_component_as_string(redirected)
112
+ else
113
+ response.body
114
+ end
115
+ end
116
+ end
117
+
118
+ def flash_with_components(refresh = false) #:nodoc:
119
+ if @flash.nil? || refresh
120
+ @flash =
121
+ if @parent_controller
122
+ @parent_controller.flash
123
+ else
124
+ flash_without_components
125
+ end
126
+ end
127
+
128
+ @flash
129
+ end
130
+
131
+ private
132
+ def component_response(options, reuse_response)
133
+ klass = component_class(options)
134
+ request = request_for_component(klass.controller_name, options)
135
+ response = reuse_response ? @response : @response.dup
136
+
137
+ klass.process_with_components(request, response, self)
138
+ end
139
+
140
+ # determine the controller class for the component request
141
+ def component_class(options)
142
+ if controller = options[:controller]
143
+ controller.is_a?(Class) ? controller : "#{controller.camelize}Controller".constantize
144
+ else
145
+ self.class
146
+ end
147
+ end
148
+
149
+ # Create a new request object based on the current request.
150
+ # The new request inherits the session from the current request,
151
+ # bypassing any session options set for the component controller's class
152
+ def request_for_component(controller_name, options)
153
+ request = @request.dup
154
+ request.session = @request.session
155
+
156
+ request.instance_variable_set(
157
+ :@parameters,
158
+ (options[:params] || {}).with_indifferent_access.update(
159
+ "controller" => controller_name, "action" => options[:action], "id" => options[:id]
160
+ )
161
+ )
162
+
163
+ request
164
+ end
165
+
166
+ def component_logging(options)
167
+ if logger
168
+ logger.info "Start rendering component (#{options.inspect}): "
169
+ result = yield
170
+ logger.info "\n\nEnd of component rendering"
171
+ result
172
+ else
173
+ yield
174
+ end
175
+ end
176
+
177
+ def set_session_options_with_components(request)
178
+ set_session_options_without_components(request) unless component_request?
179
+ end
180
+
181
+ def process_cleanup_with_components
182
+ process_cleanup_without_components unless component_request?
183
+ end
184
+ end
85
185
  end
86
186
  end
@@ -28,7 +28,7 @@ module ActionController #:nodoc:
28
28
  #
29
29
  # Also note, that if the models follow the pattern of just 1 class per file in the form of MyClass => my_class.rb, then these
30
30
  # classes don't have to be required as Active Support will auto-require them.
31
- module ClassMethods
31
+ module ClassMethods #:nodoc:
32
32
  # Specifies a variable number of models that this controller depends on. Models are normally Active Record classes or a similar
33
33
  # backend for modelling entity classes.
34
34
  def model(*models)
@@ -2,14 +2,14 @@ module ActionController
2
2
  class Base
3
3
  protected
4
4
  # Deprecated in favor of calling redirect_to directly with the path.
5
- def redirect_to_path(path)
5
+ def redirect_to_path(path) #:nodoc:
6
6
  redirect_to(path)
7
7
  end
8
8
 
9
9
  # Deprecated in favor of calling redirect_to directly with the url. If the resource has moved permanently, it's possible to pass
10
10
  # true as the second parameter and the browser will get "301 Moved Permanently" instead of "302 Found". This can also be done through
11
11
  # just setting the headers["Status"] to "301 Moved Permanently" before using the redirect_to.
12
- def redirect_to_url(url, permanently = false)
12
+ def redirect_to_url(url, permanently = false) #:nodoc:
13
13
  headers["Status"] = "301 Moved Permanently" if permanently
14
14
  redirect_to(url)
15
15
  end
@@ -0,0 +1,34 @@
1
+ module ActionController
2
+ class AbstractRequest
3
+ # Determine whether the body of a HTTP call is URL-encoded (default)
4
+ # or matches one of the registered param_parsers.
5
+ #
6
+ # For backward compatibility, the post format is extracted from the
7
+ # X-Post-Data-Format HTTP header if present.
8
+ def post_format
9
+ case content_type.to_s
10
+ when 'application/xml'
11
+ :xml
12
+ when 'application/x-yaml'
13
+ :yaml
14
+ else
15
+ :url_encoded
16
+ end
17
+ end
18
+
19
+ # Is this a POST request formatted as XML or YAML?
20
+ def formatted_post?
21
+ post? && (post_format == :yaml || post_format == :xml)
22
+ end
23
+
24
+ # Is this a POST request formatted as XML?
25
+ def xml_post?
26
+ post? && post_format == :xml
27
+ end
28
+
29
+ # Is this a POST request formatted as YAML?
30
+ def yaml_post?
31
+ post? && post_format == :yaml
32
+ end
33
+ end
34
+ end
@@ -1,7 +1,6 @@
1
1
  module ActionController #:nodoc:
2
2
  module Filters #:nodoc:
3
- def self.append_features(base)
4
- super
3
+ def self.included(base)
5
4
  base.extend(ClassMethods)
6
5
  base.send(:include, ActionController::Filters::InstanceMethods)
7
6
  end
@@ -141,7 +140,7 @@ module ActionController #:nodoc:
141
140
  # # will run the :authenticate filter
142
141
  # end
143
142
  #
144
- # class SignupController < ActionController::Base
143
+ # class SignupController < ApplicationController
145
144
  # # will not run the :authenticate filter
146
145
  # skip_before_filter :authenticate
147
146
  # end
@@ -251,39 +250,55 @@ module ActionController #:nodoc:
251
250
  # Removes the specified filters from the +before+ filter chain. Note that this only works for skipping method-reference
252
251
  # filters, not procs. This is especially useful for managing the chain in inheritance hierarchies where only one out
253
252
  # of many sub-controllers need a different hierarchy.
253
+ #
254
+ # You can control the actions to skip the filter for with the <tt>:only</tt> and <tt>:except</tt> options,
255
+ # just like when you apply the filters.
254
256
  def skip_before_filter(*filters)
255
- for filter in filters.flatten
256
- write_inheritable_attribute("before_filters", read_inheritable_attribute("before_filters") - [ filter ])
257
+ if conditions = extract_conditions!(filters)
258
+ conditions[:only], conditions[:except] = conditions[:except], conditions[:only]
259
+ add_action_conditions(filters, conditions)
260
+ else
261
+ for filter in filters.flatten
262
+ write_inheritable_attribute("before_filters", read_inheritable_attribute("before_filters") - [ filter ])
263
+ end
257
264
  end
258
265
  end
259
266
 
260
267
  # Removes the specified filters from the +after+ filter chain. Note that this only works for skipping method-reference
261
268
  # filters, not procs. This is especially useful for managing the chain in inheritance hierarchies where only one out
262
269
  # of many sub-controllers need a different hierarchy.
270
+ #
271
+ # You can control the actions to skip the filter for with the <tt>:only</tt> and <tt>:except</tt> options,
272
+ # just like when you apply the filters.
263
273
  def skip_after_filter(*filters)
264
- for filter in filters.flatten
265
- write_inheritable_attribute("after_filters", read_inheritable_attribute("after_filters") - [ filter ])
274
+ if conditions = extract_conditions!(filters)
275
+ conditions[:only], conditions[:except] = conditions[:except], conditions[:only]
276
+ add_action_conditions(filters, conditions)
277
+ else
278
+ for filter in filters.flatten
279
+ write_inheritable_attribute("after_filters", read_inheritable_attribute("after_filters") - [ filter ])
280
+ end
266
281
  end
267
282
  end
268
283
 
269
284
  # Returns all the before filters for this class and all its ancestors.
270
285
  def before_filters #:nodoc:
271
- read_inheritable_attribute("before_filters")
286
+ @before_filters ||= read_inheritable_attribute("before_filters") || []
272
287
  end
273
288
 
274
289
  # Returns all the after filters for this class and all its ancestors.
275
290
  def after_filters #:nodoc:
276
- read_inheritable_attribute("after_filters")
291
+ @after_filters ||= read_inheritable_attribute("after_filters") || []
277
292
  end
278
293
 
279
294
  # Returns a mapping between filters and the actions that may run them.
280
295
  def included_actions #:nodoc:
281
- read_inheritable_attribute("included_actions") || {}
296
+ @included_actions ||= read_inheritable_attribute("included_actions") || {}
282
297
  end
283
298
 
284
299
  # Returns a mapping between filters and actions that may not run them.
285
300
  def excluded_actions #:nodoc:
286
- read_inheritable_attribute("excluded_actions") || {}
301
+ @excluded_actions ||= read_inheritable_attribute("excluded_actions") || {}
287
302
  end
288
303
 
289
304
  private
@@ -292,7 +307,8 @@ module ActionController #:nodoc:
292
307
  end
293
308
 
294
309
  def prepend_filter_to_chain(condition, filters)
295
- write_inheritable_attribute("#{condition}_filters", filters + read_inheritable_attribute("#{condition}_filters"))
310
+ old_filters = read_inheritable_attribute("#{condition}_filters") || []
311
+ write_inheritable_attribute("#{condition}_filters", filters + old_filters)
296
312
  end
297
313
 
298
314
  def ensure_filter_responds_to_before_and_after(filter)
@@ -319,18 +335,33 @@ module ActionController #:nodoc:
319
335
  end
320
336
 
321
337
  module InstanceMethods # :nodoc:
322
- def self.append_features(base)
323
- super
324
- base.class_eval {
338
+ def self.included(base)
339
+ base.class_eval do
325
340
  alias_method :perform_action_without_filters, :perform_action
326
341
  alias_method :perform_action, :perform_action_with_filters
327
- }
342
+
343
+ alias_method :process_without_filters, :process
344
+ alias_method :process, :process_with_filters
345
+
346
+ alias_method :process_cleanup_without_filters, :process_cleanup
347
+ alias_method :process_cleanup, :process_cleanup_with_filters
348
+ end
328
349
  end
329
350
 
330
351
  def perform_action_with_filters
331
- return if before_action == false || performed?
332
- perform_action_without_filters
333
- after_action
352
+ before_action_result = before_action
353
+
354
+ unless before_action_result == false || performed?
355
+ perform_action_without_filters
356
+ after_action
357
+ end
358
+
359
+ @before_filter_chain_aborted = (before_action_result == false)
360
+ end
361
+
362
+ def process_with_filters(request, response, method = :perform_action, *arguments) #:nodoc:
363
+ @before_filter_chain_aborted = false
364
+ process_without_filters(request, response, method, *arguments)
334
365
  end
335
366
 
336
367
  # Calls all the defined before-filter filters, which are added by using "before_filter :method".
@@ -349,6 +380,7 @@ module ActionController #:nodoc:
349
380
  def call_filters(filters)
350
381
  filters.each do |filter|
351
382
  next if action_exempted?(filter)
383
+
352
384
  filter_result = case
353
385
  when filter.is_a?(Symbol)
354
386
  self.send(filter)
@@ -386,6 +418,14 @@ module ActionController #:nodoc:
386
418
  ea.include?(action_name)
387
419
  end
388
420
  end
421
+
422
+ def process_cleanup_with_filters
423
+ if @before_filter_chain_aborted
424
+ close_session
425
+ else
426
+ process_cleanup_without_filters
427
+ end
428
+ end
389
429
  end
390
430
  end
391
431
  end