actionpack 2.1.0 → 2.1.1

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 (60) hide show
  1. data/CHANGELOG +17 -0
  2. data/Rakefile +10 -6
  3. data/lib/action_controller.rb +0 -0
  4. data/lib/action_controller/assertions/response_assertions.rb +1 -1
  5. data/lib/action_controller/assertions/selector_assertions.rb +26 -46
  6. data/lib/action_controller/base.rb +8 -4
  7. data/lib/action_controller/dispatcher.rb +1 -1
  8. data/lib/action_controller/filters.rb +194 -195
  9. data/lib/action_controller/polymorphic_routes.rb +25 -12
  10. data/lib/action_controller/record_identifier.rb +20 -13
  11. data/lib/action_controller/request.rb +9 -6
  12. data/lib/action_controller/request_profiler.rb +0 -0
  13. data/lib/action_controller/response.rb +0 -0
  14. data/lib/action_controller/routing.rb +5 -1
  15. data/lib/action_controller/routing/builder.rb +1 -2
  16. data/lib/action_controller/routing/segments.rb +1 -1
  17. data/lib/action_controller/templates/rescues/layout.erb +1 -1
  18. data/lib/action_controller/test_process.rb +4 -2
  19. data/lib/action_controller/vendor/html-scanner/html/document.rb +1 -1
  20. data/lib/action_controller/verification.rb +1 -1
  21. data/lib/action_pack/version.rb +1 -1
  22. data/lib/action_view/base.rb +7 -3
  23. data/lib/action_view/helpers/asset_tag_helper.rb +14 -11
  24. data/lib/action_view/helpers/date_helper.rb +3 -3
  25. data/lib/action_view/helpers/form_helper.rb +5 -1
  26. data/lib/action_view/helpers/form_options_helper.rb +2 -2
  27. data/lib/action_view/helpers/form_tag_helper.rb +5 -3
  28. data/lib/action_view/helpers/javascript_helper.rb +4 -4
  29. data/lib/action_view/helpers/prototype_helper.rb +7 -7
  30. data/lib/action_view/helpers/tag_helper.rb +4 -3
  31. data/lib/action_view/helpers/text_helper.rb +1 -1
  32. data/lib/action_view/helpers/url_helper.rb +3 -5
  33. data/lib/action_view/partial_template.rb +1 -1
  34. data/test/controller/action_pack_assertions_test.rb +24 -5
  35. data/test/controller/assert_select_test.rb +6 -1
  36. data/test/controller/base_test.rb +37 -1
  37. data/test/controller/cgi_test.rb +0 -0
  38. data/test/controller/dispatcher_test.rb +2 -2
  39. data/test/controller/html-scanner/document_test.rb +25 -0
  40. data/test/controller/integration_upload_test.rb +1 -1
  41. data/test/controller/new_render_test.rb +22 -3
  42. data/test/controller/polymorphic_routes_test.rb +33 -0
  43. data/test/controller/redirect_test.rb +0 -0
  44. data/test/controller/render_test.rb +1 -1
  45. data/test/controller/request_test.rb +6 -0
  46. data/test/controller/resources_test.rb +15 -17
  47. data/test/controller/routing_test.rb +22 -2
  48. data/test/controller/session/cookie_store_test.rb +0 -0
  49. data/test/controller/test_test.rb +11 -2
  50. data/test/controller/verification_test.rb +34 -17
  51. data/test/fixtures/test/render_file_from_template.html.erb +1 -0
  52. data/test/template/date_helper_test.rb +59 -8
  53. data/test/template/deprecated_erb_variable_test.rb +9 -0
  54. data/test/template/form_options_helper_test.rb +505 -514
  55. data/test/template/form_tag_helper_test.rb +13 -0
  56. data/test/template/javascript_helper_test.rb +7 -4
  57. data/test/template/prototype_helper_test.rb +14 -6
  58. data/test/template/text_helper_test.rb +1 -0
  59. data/test/template/url_helper_test.rb +11 -1
  60. metadata +8 -4
data/CHANGELOG CHANGED
@@ -1,3 +1,20 @@
1
+ *2.1.1 (September 4th, 2008)*
2
+
3
+ * All 2xx requests are considered successful [Josh Peek]
4
+
5
+ * Deprecate the limited follow_redirect in functional tests. If you wish to follow redirects, use integration tests. [Michael Koziarski]
6
+
7
+ * Fixed that AssetTagHelper#compute_public_path shouldn't cache the asset_host along with the source or per-request proc's won't run [DHH]
8
+
9
+ * Deprecate define_javascript_functions, javascript_include_tag and friends are much better [Michael Koziarski]
10
+
11
+ * Fix polymorphic_url with singleton resources. #461 [Tammer Saleh]
12
+
13
+ * Deprecate ActionView::Base.erb_variable. Use the concat helper method instead of appending to it directly. [Jeremy Kemper]
14
+
15
+ * Fixed Request#remote_ip to only raise hell if the HTTP_CLIENT_IP and HTTP_X_FORWARDED_FOR doesn't match (not just if they're both present) [Mark Imbriaco, Bradford Folkens]
16
+
17
+
1
18
  *2.1.0 (May 31st, 2008)*
2
19
 
3
20
  * InstanceTag#default_time_from_options overflows to DateTime [Geoff Buesing]
data/Rakefile CHANGED
@@ -5,6 +5,8 @@ require 'rake/rdoctask'
5
5
  require 'rake/packagetask'
6
6
  require 'rake/gempackagetask'
7
7
  require 'rake/contrib/sshpublisher'
8
+ require 'rake/contrib/rubyforgepublisher'
9
+
8
10
  require File.join(File.dirname(__FILE__), 'lib', 'action_pack', 'version')
9
11
 
10
12
  PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
@@ -49,12 +51,14 @@ Rake::RDocTask.new { |rdoc|
49
51
  rdoc.title = "Action Pack -- On rails from request to response"
50
52
  rdoc.options << '--line-numbers' << '--inline-source'
51
53
  rdoc.options << '--charset' << 'utf-8'
52
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
54
+ rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
53
55
  if ENV['DOC_FILES']
54
56
  rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
55
57
  else
56
58
  rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
57
- rdoc.rdoc_files.include('lib/**/*.rb')
59
+ rdoc.rdoc_files.include(Dir['lib/**/*.rb'] -
60
+ Dir['lib/*/vendor/**/*.rb'])
61
+ rdoc.rdoc_files.exclude('lib/actionpack.rb')
58
62
  end
59
63
  }
60
64
 
@@ -76,7 +80,7 @@ spec = Gem::Specification.new do |s|
76
80
  s.has_rdoc = true
77
81
  s.requirements << 'none'
78
82
 
79
- s.add_dependency('activesupport', '= 2.1.0' + PKG_BUILD)
83
+ s.add_dependency('activesupport', '= 2.1.1' + PKG_BUILD)
80
84
 
81
85
  s.require_path = 'lib'
82
86
  s.autorequire = 'action_controller'
@@ -132,13 +136,13 @@ task :update_js => [ :update_scriptaculous ]
132
136
 
133
137
  desc "Publish the API documentation"
134
138
  task :pgem => [:package] do
135
- Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
136
- `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'`
139
+ Rake::SshFilePublisher.new("david@greed.loudthinking.com", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
140
+ `ssh david@greed.loudthinking.com '/u/sites/gems/gemupdate.sh'`
137
141
  end
138
142
 
139
143
  desc "Publish the API documentation"
140
144
  task :pdoc => [:rdoc] do
141
- Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/ap", "doc").upload
145
+ Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ap", "doc").upload
142
146
  end
143
147
 
144
148
  desc "Publish the release files to RubyForge."
File without changes
@@ -97,7 +97,7 @@ module ActionController
97
97
  value['controller'] = value['controller'].to_s
98
98
  if key == :actual && value['controller'].first != '/' && !value['controller'].include?('/')
99
99
  new_controller_path = ActionController::Routing.controller_relative_to(value['controller'], @controller.class.controller_path)
100
- value['controller'] = new_controller_path if value['controller'] != new_controller_path && ActionController::Routing.possible_controllers.include?(new_controller_path)
100
+ value['controller'] = new_controller_path if value['controller'] != new_controller_path && ActionController::Routing.possible_controllers.include?(new_controller_path) && @response.redirected_to.is_a?(Hash)
101
101
  end
102
102
  value['controller'] = value['controller'][1..-1] if value['controller'].first == '/' # strip leading hash
103
103
  end
@@ -398,47 +398,31 @@ module ActionController
398
398
  # # The same, but shorter.
399
399
  # assert_select "ol>li", 4
400
400
  def assert_select_rjs(*args, &block)
401
- rjs_type = nil
402
- arg = args.shift
401
+ rjs_type = args.first.is_a?(Symbol) ? args.shift : nil
402
+ id = args.first.is_a?(String) ? args.shift : nil
403
403
 
404
404
  # If the first argument is a symbol, it's the type of RJS statement we're looking
405
405
  # for (update, replace, insertion, etc). Otherwise, we're looking for just about
406
406
  # any RJS statement.
407
- if arg.is_a?(Symbol)
408
- rjs_type = arg
409
-
407
+ if rjs_type
410
408
  if rjs_type == :insert
411
- arg = args.shift
412
- insertion = "insert_#{arg}".to_sym
413
- raise ArgumentError, "Unknown RJS insertion type #{arg}" unless RJS_STATEMENTS[insertion]
409
+ position = args.shift
410
+ insertion = "insert_#{position}".to_sym
411
+ raise ArgumentError, "Unknown RJS insertion type #{position}" unless RJS_STATEMENTS[insertion]
414
412
  statement = "(#{RJS_STATEMENTS[insertion]})"
415
413
  else
416
414
  raise ArgumentError, "Unknown RJS statement type #{rjs_type}" unless RJS_STATEMENTS[rjs_type]
417
415
  statement = "(#{RJS_STATEMENTS[rjs_type]})"
418
416
  end
419
- arg = args.shift
420
417
  else
421
418
  statement = "#{RJS_STATEMENTS[:any]}"
422
419
  end
423
420
 
424
421
  # Next argument we're looking for is the element identifier. If missing, we pick
425
- # any element.
426
- if arg.is_a?(String)
427
- id = Regexp.quote(arg)
428
- arg = args.shift
429
- else
430
- id = "[^\"]*"
431
- end
432
-
433
- pattern =
434
- case rjs_type
435
- when :chained_replace, :chained_replace_html
436
- Regexp.new("\\$\\(\"#{id}\"\\)#{statement}\\(#{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
437
- when :remove, :show, :hide, :toggle
438
- Regexp.new("#{statement}\\(\"#{id}\"\\)")
439
- else
440
- Regexp.new("#{statement}\\(\"#{id}\", #{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
441
- end
422
+ # any element, otherwise we replace it in the statement.
423
+ pattern = Regexp.new(
424
+ id ? statement.gsub(RJS_ANY_ID, "\"#{id}\"") : statement
425
+ )
442
426
 
443
427
  # Duplicate the body since the next step involves destroying it.
444
428
  matches = nil
@@ -447,7 +431,7 @@ module ActionController
447
431
  matches = @response.body.match(pattern)
448
432
  else
449
433
  @response.body.gsub(pattern) do |match|
450
- html = unescape_rjs($2)
434
+ html = unescape_rjs(match)
451
435
  matches ||= []
452
436
  matches.concat HTML::Document.new(html).root.children.select { |n| n.tag? }
453
437
  ""
@@ -577,27 +561,23 @@ module ActionController
577
561
 
578
562
  protected
579
563
  unless const_defined?(:RJS_STATEMENTS)
580
- RJS_STATEMENTS = {
581
- :replace => /Element\.replace/,
582
- :replace_html => /Element\.update/,
583
- :chained_replace => /\.replace/,
584
- :chained_replace_html => /\.update/,
585
- :remove => /Element\.remove/,
586
- :show => /Element\.show/,
587
- :hide => /Element\.hide/,
588
- :toggle => /Element\.toggle/
564
+ RJS_PATTERN_HTML = "\"((\\\\\"|[^\"])*)\""
565
+ RJS_ANY_ID = "\"([^\"])*\""
566
+ RJS_STATEMENTS = {
567
+ :chained_replace => "\\$\\(#{RJS_ANY_ID}\\)\\.replace\\(#{RJS_PATTERN_HTML}\\)",
568
+ :chained_replace_html => "\\$\\(#{RJS_ANY_ID}\\)\\.update\\(#{RJS_PATTERN_HTML}\\)",
569
+ :replace_html => "Element\\.update\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)",
570
+ :replace => "Element\\.replace\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)"
589
571
  }
590
- RJS_INSERTIONS = [:top, :bottom, :before, :after]
572
+ [:remove, :show, :hide, :toggle].each do |action|
573
+ RJS_STATEMENTS[action] = "Element\\.#{action}\\(#{RJS_ANY_ID}\\)"
574
+ end
575
+ RJS_INSERTIONS = ["top", "bottom", "before", "after"]
591
576
  RJS_INSERTIONS.each do |insertion|
592
- RJS_STATEMENTS["insert_#{insertion}".to_sym] = Regexp.new(Regexp.quote("new Insertion.#{insertion.to_s.camelize}"))
577
+ RJS_STATEMENTS["insert_#{insertion}".to_sym] = "Element.insert\\(#{RJS_ANY_ID}, \\{ #{insertion}: #{RJS_PATTERN_HTML} \\}\\)"
593
578
  end
579
+ RJS_STATEMENTS[:insert_html] = "Element.insert\\(#{RJS_ANY_ID}, \\{ (#{RJS_INSERTIONS.join('|')}): #{RJS_PATTERN_HTML} \\}\\)"
594
580
  RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})")
595
- RJS_STATEMENTS[:insert_html] = Regexp.new(RJS_INSERTIONS.collect do |insertion|
596
- Regexp.quote("new Insertion.#{insertion.to_s.camelize}")
597
- end.join('|'))
598
- RJS_PATTERN_HTML = /"((\\"|[^"])*)"/
599
- RJS_PATTERN_EVERYTHING = Regexp.new("#{RJS_STATEMENTS[:any]}\\(\"([^\"]*)\", #{RJS_PATTERN_HTML}\\)",
600
- Regexp::MULTILINE)
601
581
  RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/
602
582
  end
603
583
 
@@ -611,8 +591,8 @@ module ActionController
611
591
  root = HTML::Node.new(nil)
612
592
 
613
593
  while true
614
- next if body.sub!(RJS_PATTERN_EVERYTHING) do |match|
615
- html = unescape_rjs($3)
594
+ next if body.sub!(RJS_STATEMENTS[:any]) do |match|
595
+ html = unescape_rjs(match)
616
596
  matches = HTML::Document.new(html).root.children.select { |n| n.tag? }
617
597
  root.children.concat matches
618
598
  ""
@@ -613,8 +613,9 @@ module ActionController #:nodoc:
613
613
  #
614
614
  # This takes the current URL as is and only exchanges the action. In contrast, <tt>url_for :action => 'print'</tt>
615
615
  # would have slashed-off the path components after the changed action.
616
- def url_for(options = nil) #:doc:
617
- case options || {}
616
+ def url_for(options = {})
617
+ options ||= {}
618
+ case options
618
619
  when String
619
620
  options
620
621
  when Hash
@@ -743,6 +744,9 @@ module ActionController #:nodoc:
743
744
  # # Renders the template located in [TEMPLATE_ROOT]/weblog/show.r(html|xml) (in Rails, app/views/weblog/show.erb)
744
745
  # render :template => "weblog/show"
745
746
  #
747
+ # # Renders the template with a local variable
748
+ # render :template => "weblog/show", :locals => {:customer => Customer.new}
749
+ #
746
750
  # === Rendering a file
747
751
  #
748
752
  # File rendering works just like action rendering except that it takes a filesystem path. By default, the path
@@ -865,7 +869,7 @@ module ActionController #:nodoc:
865
869
  render_for_file(file, options[:status], options[:use_full_path], options[:locals] || {})
866
870
 
867
871
  elsif template = options[:template]
868
- render_for_file(template, options[:status], true)
872
+ render_for_file(template, options[:status], true, options[:locals] || {})
869
873
 
870
874
  elsif inline = options[:inline]
871
875
  add_variables_to_assigns
@@ -1147,7 +1151,7 @@ module ActionController #:nodoc:
1147
1151
 
1148
1152
  def log_processing
1149
1153
  if logger && logger.info?
1150
- logger.info "\n\nProcessing #{controller_class_name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
1154
+ logger.info "\n\nProcessing #{self.class.name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
1151
1155
  logger.info " Session ID: #{@_session.session_id}" if @_session and @_session.respond_to?(:session_id)
1152
1156
  logger.info " Parameters: #{respond_to?(:filter_parameters) ? filter_parameters(params).inspect : params.inspect}"
1153
1157
  end
@@ -135,7 +135,7 @@ module ActionController
135
135
  # be reloaded on the next request without restarting the server.
136
136
  def cleanup_application
137
137
  ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
138
- Dependencies.clear
138
+ ActiveSupport::Dependencies.clear
139
139
  ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
140
140
  end
141
141
 
@@ -7,6 +7,200 @@ module ActionController #:nodoc:
7
7
  end
8
8
  end
9
9
 
10
+ class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc:
11
+ def append_filter_to_chain(filters, filter_type, &block)
12
+ pos = find_filter_append_position(filters, filter_type)
13
+ update_filter_chain(filters, filter_type, pos, &block)
14
+ end
15
+
16
+ def prepend_filter_to_chain(filters, filter_type, &block)
17
+ pos = find_filter_prepend_position(filters, filter_type)
18
+ update_filter_chain(filters, filter_type, pos, &block)
19
+ end
20
+
21
+ def create_filters(filters, filter_type, &block)
22
+ filters, conditions = extract_options(filters, &block)
23
+ filters.map! { |filter| find_or_create_filter(filter, filter_type, conditions) }
24
+ filters
25
+ end
26
+
27
+ def skip_filter_in_chain(*filters, &test)
28
+ filters, conditions = extract_options(filters)
29
+ filters.each do |filter|
30
+ if callback = find(filter) then delete(callback) end
31
+ end if conditions.empty?
32
+ update_filter_in_chain(filters, :skip => conditions, &test)
33
+ end
34
+
35
+ private
36
+ def update_filter_chain(filters, filter_type, pos, &block)
37
+ new_filters = create_filters(filters, filter_type, &block)
38
+ insert(pos, new_filters).flatten!
39
+ end
40
+
41
+ def find_filter_append_position(filters, filter_type)
42
+ # appending an after filter puts it at the end of the call chain
43
+ # before and around filters go before the first after filter in the chain
44
+ unless filter_type == :after
45
+ each_with_index do |f,i|
46
+ return i if f.after?
47
+ end
48
+ end
49
+ return -1
50
+ end
51
+
52
+ def find_filter_prepend_position(filters, filter_type)
53
+ # prepending a before or around filter puts it at the front of the call chain
54
+ # after filters go before the first after filter in the chain
55
+ if filter_type == :after
56
+ each_with_index do |f,i|
57
+ return i if f.after?
58
+ end
59
+ return -1
60
+ end
61
+ return 0
62
+ end
63
+
64
+ def find_or_create_filter(filter, filter_type, options = {})
65
+ update_filter_in_chain([filter], options)
66
+
67
+ if found_filter = find(filter) { |f| f.type == filter_type }
68
+ found_filter
69
+ else
70
+ filter_kind = case
71
+ when filter.respond_to?(:before) && filter_type == :before
72
+ :before
73
+ when filter.respond_to?(:after) && filter_type == :after
74
+ :after
75
+ else
76
+ :filter
77
+ end
78
+
79
+ case filter_type
80
+ when :before
81
+ BeforeFilter.new(filter_kind, filter, options)
82
+ when :after
83
+ AfterFilter.new(filter_kind, filter, options)
84
+ else
85
+ AroundFilter.new(filter_kind, filter, options)
86
+ end
87
+ end
88
+ end
89
+
90
+ def update_filter_in_chain(filters, options, &test)
91
+ filters.map! { |f| block_given? ? find(f, &test) : find(f) }
92
+ filters.compact!
93
+
94
+ map! do |filter|
95
+ if filters.include?(filter)
96
+ new_filter = filter.dup
97
+ new_filter.options.merge!(options)
98
+ new_filter
99
+ else
100
+ filter
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ class Filter < ActiveSupport::Callbacks::Callback #:nodoc:
107
+ def before?
108
+ self.class == BeforeFilter
109
+ end
110
+
111
+ def after?
112
+ self.class == AfterFilter
113
+ end
114
+
115
+ def around?
116
+ self.class == AroundFilter
117
+ end
118
+
119
+ private
120
+ def should_not_skip?(controller)
121
+ if options[:skip]
122
+ !included_in_action?(controller, options[:skip])
123
+ else
124
+ true
125
+ end
126
+ end
127
+
128
+ def included_in_action?(controller, options)
129
+ if options[:only]
130
+ Array(options[:only]).map(&:to_s).include?(controller.action_name)
131
+ elsif options[:except]
132
+ !Array(options[:except]).map(&:to_s).include?(controller.action_name)
133
+ else
134
+ true
135
+ end
136
+ end
137
+
138
+ def should_run_callback?(controller)
139
+ should_not_skip?(controller) && included_in_action?(controller, options) && super
140
+ end
141
+ end
142
+
143
+ class AroundFilter < Filter #:nodoc:
144
+ def type
145
+ :around
146
+ end
147
+
148
+ def call(controller, &block)
149
+ if should_run_callback?(controller)
150
+ method = filter_responds_to_before_and_after? ? around_proc : self.method
151
+
152
+ # For around_filter do |controller, action|
153
+ if method.is_a?(Proc) && method.arity == 2
154
+ evaluate_method(method, controller, block)
155
+ else
156
+ evaluate_method(method, controller, &block)
157
+ end
158
+ else
159
+ block.call
160
+ end
161
+ end
162
+
163
+ private
164
+ def filter_responds_to_before_and_after?
165
+ method.respond_to?(:before) && method.respond_to?(:after)
166
+ end
167
+
168
+ def around_proc
169
+ Proc.new do |controller, action|
170
+ method.before(controller)
171
+
172
+ if controller.send!(:performed?)
173
+ controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
174
+ else
175
+ begin
176
+ action.call
177
+ ensure
178
+ method.after(controller)
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
184
+
185
+ class BeforeFilter < Filter #:nodoc:
186
+ def type
187
+ :before
188
+ end
189
+
190
+ def call(controller, &block)
191
+ super
192
+ if controller.send!(:performed?)
193
+ controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
194
+ end
195
+ end
196
+ end
197
+
198
+ class AfterFilter < Filter #:nodoc:
199
+ def type
200
+ :after
201
+ end
202
+ end
203
+
10
204
  # Filters enable controllers to run shared pre- and post-processing code for its actions. These filters can be used to do
11
205
  # authentication, caching, or auditing before the intended action is performed. Or to do localization or output
12
206
  # compression after the action has been performed. Filters have access to the request, response, and all the instance
@@ -245,201 +439,6 @@ module ActionController #:nodoc:
245
439
  # filter and controller action will not be run. If +before+ renders or redirects,
246
440
  # the second half of +around+ and will still run but +after+ and the
247
441
  # action will not. If +around+ fails to yield, +after+ will not be run.
248
-
249
- class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc:
250
- def append_filter_to_chain(filters, filter_type, &block)
251
- pos = find_filter_append_position(filters, filter_type)
252
- update_filter_chain(filters, filter_type, pos, &block)
253
- end
254
-
255
- def prepend_filter_to_chain(filters, filter_type, &block)
256
- pos = find_filter_prepend_position(filters, filter_type)
257
- update_filter_chain(filters, filter_type, pos, &block)
258
- end
259
-
260
- def create_filters(filters, filter_type, &block)
261
- filters, conditions = extract_options(filters, &block)
262
- filters.map! { |filter| find_or_create_filter(filter, filter_type, conditions) }
263
- filters
264
- end
265
-
266
- def skip_filter_in_chain(*filters, &test)
267
- filters, conditions = extract_options(filters)
268
- filters.each do |filter|
269
- if callback = find(filter) then delete(callback) end
270
- end if conditions.empty?
271
- update_filter_in_chain(filters, :skip => conditions, &test)
272
- end
273
-
274
- private
275
- def update_filter_chain(filters, filter_type, pos, &block)
276
- new_filters = create_filters(filters, filter_type, &block)
277
- insert(pos, new_filters).flatten!
278
- end
279
-
280
- def find_filter_append_position(filters, filter_type)
281
- # appending an after filter puts it at the end of the call chain
282
- # before and around filters go before the first after filter in the chain
283
- unless filter_type == :after
284
- each_with_index do |f,i|
285
- return i if f.after?
286
- end
287
- end
288
- return -1
289
- end
290
-
291
- def find_filter_prepend_position(filters, filter_type)
292
- # prepending a before or around filter puts it at the front of the call chain
293
- # after filters go before the first after filter in the chain
294
- if filter_type == :after
295
- each_with_index do |f,i|
296
- return i if f.after?
297
- end
298
- return -1
299
- end
300
- return 0
301
- end
302
-
303
- def find_or_create_filter(filter, filter_type, options = {})
304
- update_filter_in_chain([filter], options)
305
-
306
- if found_filter = find(filter) { |f| f.type == filter_type }
307
- found_filter
308
- else
309
- filter_kind = case
310
- when filter.respond_to?(:before) && filter_type == :before
311
- :before
312
- when filter.respond_to?(:after) && filter_type == :after
313
- :after
314
- else
315
- :filter
316
- end
317
-
318
- case filter_type
319
- when :before
320
- BeforeFilter.new(filter_kind, filter, options)
321
- when :after
322
- AfterFilter.new(filter_kind, filter, options)
323
- else
324
- AroundFilter.new(filter_kind, filter, options)
325
- end
326
- end
327
- end
328
-
329
- def update_filter_in_chain(filters, options, &test)
330
- filters.map! { |f| block_given? ? find(f, &test) : find(f) }
331
- filters.compact!
332
-
333
- map! do |filter|
334
- if filters.include?(filter)
335
- new_filter = filter.dup
336
- new_filter.options.merge!(options)
337
- new_filter
338
- else
339
- filter
340
- end
341
- end
342
- end
343
- end
344
-
345
- class Filter < ActiveSupport::Callbacks::Callback #:nodoc:
346
- def before?
347
- self.class == BeforeFilter
348
- end
349
-
350
- def after?
351
- self.class == AfterFilter
352
- end
353
-
354
- def around?
355
- self.class == AroundFilter
356
- end
357
-
358
- private
359
- def should_not_skip?(controller)
360
- if options[:skip]
361
- !included_in_action?(controller, options[:skip])
362
- else
363
- true
364
- end
365
- end
366
-
367
- def included_in_action?(controller, options)
368
- if options[:only]
369
- Array(options[:only]).map(&:to_s).include?(controller.action_name)
370
- elsif options[:except]
371
- !Array(options[:except]).map(&:to_s).include?(controller.action_name)
372
- else
373
- true
374
- end
375
- end
376
-
377
- def should_run_callback?(controller)
378
- should_not_skip?(controller) && included_in_action?(controller, options) && super
379
- end
380
- end
381
-
382
- class AroundFilter < Filter #:nodoc:
383
- def type
384
- :around
385
- end
386
-
387
- def call(controller, &block)
388
- if should_run_callback?(controller)
389
- method = filter_responds_to_before_and_after? ? around_proc : self.method
390
-
391
- # For around_filter do |controller, action|
392
- if method.is_a?(Proc) && method.arity == 2
393
- evaluate_method(method, controller, block)
394
- else
395
- evaluate_method(method, controller, &block)
396
- end
397
- else
398
- block.call
399
- end
400
- end
401
-
402
- private
403
- def filter_responds_to_before_and_after?
404
- method.respond_to?(:before) && method.respond_to?(:after)
405
- end
406
-
407
- def around_proc
408
- Proc.new do |controller, action|
409
- method.before(controller)
410
-
411
- if controller.send!(:performed?)
412
- controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
413
- else
414
- begin
415
- action.call
416
- ensure
417
- method.after(controller)
418
- end
419
- end
420
- end
421
- end
422
- end
423
-
424
- class BeforeFilter < Filter #:nodoc:
425
- def type
426
- :before
427
- end
428
-
429
- def call(controller, &block)
430
- super
431
- if controller.send!(:performed?)
432
- controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
433
- end
434
- end
435
- end
436
-
437
- class AfterFilter < Filter #:nodoc:
438
- def type
439
- :after
440
- end
441
- end
442
-
443
442
  module ClassMethods
444
443
  # The passed <tt>filters</tt> will be appended to the filter_chain and
445
444
  # will execute before the action on this controller is performed.