actionpack 1.9.1 → 1.10.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 (123) hide show
  1. data/CHANGELOG +237 -0
  2. data/README +12 -12
  3. data/lib/action_controller.rb +17 -12
  4. data/lib/action_controller/assertions.rb +119 -67
  5. data/lib/action_controller/base.rb +184 -102
  6. data/lib/action_controller/benchmarking.rb +35 -6
  7. data/lib/action_controller/caching.rb +115 -58
  8. data/lib/action_controller/cgi_ext/cgi_methods.rb +54 -21
  9. data/lib/action_controller/cgi_ext/cookie_performance_fix.rb +39 -35
  10. data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +34 -21
  11. data/lib/action_controller/cgi_process.rb +23 -20
  12. data/lib/action_controller/components.rb +11 -2
  13. data/lib/action_controller/dependencies.rb +0 -5
  14. data/lib/action_controller/deprecated_redirects.rb +17 -0
  15. data/lib/action_controller/filters.rb +13 -9
  16. data/lib/action_controller/flash.rb +7 -7
  17. data/lib/action_controller/helpers.rb +1 -14
  18. data/lib/action_controller/layout.rb +40 -29
  19. data/lib/action_controller/macros/auto_complete.rb +52 -0
  20. data/lib/action_controller/macros/in_place_editing.rb +32 -0
  21. data/lib/action_controller/pagination.rb +44 -28
  22. data/lib/action_controller/request.rb +54 -40
  23. data/lib/action_controller/rescue.rb +8 -6
  24. data/lib/action_controller/routing.rb +77 -28
  25. data/lib/action_controller/scaffolding.rb +10 -14
  26. data/lib/action_controller/session/active_record_store.rb +36 -7
  27. data/lib/action_controller/session_management.rb +126 -0
  28. data/lib/action_controller/streaming.rb +14 -5
  29. data/lib/action_controller/templates/rescues/_request_and_response.rhtml +1 -1
  30. data/lib/action_controller/templates/rescues/_trace.rhtml +24 -0
  31. data/lib/action_controller/templates/rescues/diagnostics.rhtml +2 -13
  32. data/lib/action_controller/templates/rescues/template_error.rhtml +4 -2
  33. data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
  34. data/lib/action_controller/test_process.rb +35 -17
  35. data/lib/action_controller/upload_progress.rb +52 -0
  36. data/lib/action_controller/url_rewriter.rb +21 -16
  37. data/lib/action_controller/vendor/html-scanner/html/document.rb +2 -2
  38. data/lib/action_controller/vendor/html-scanner/html/node.rb +30 -3
  39. data/lib/action_pack/version.rb +9 -0
  40. data/lib/action_view.rb +1 -1
  41. data/lib/action_view/base.rb +204 -60
  42. data/lib/action_view/compiled_templates.rb +70 -0
  43. data/lib/action_view/helpers/active_record_helper.rb +7 -3
  44. data/lib/action_view/helpers/asset_tag_helper.rb +22 -12
  45. data/lib/action_view/helpers/capture_helper.rb +2 -10
  46. data/lib/action_view/helpers/date_helper.rb +21 -13
  47. data/lib/action_view/helpers/form_helper.rb +14 -10
  48. data/lib/action_view/helpers/form_options_helper.rb +4 -4
  49. data/lib/action_view/helpers/form_tag_helper.rb +59 -25
  50. data/lib/action_view/helpers/java_script_macros_helper.rb +188 -0
  51. data/lib/action_view/helpers/javascript_helper.rb +68 -133
  52. data/lib/action_view/helpers/javascripts/controls.js +427 -165
  53. data/lib/action_view/helpers/javascripts/dragdrop.js +256 -277
  54. data/lib/action_view/helpers/javascripts/effects.js +766 -277
  55. data/lib/action_view/helpers/javascripts/prototype.js +906 -218
  56. data/lib/action_view/helpers/javascripts/slider.js +258 -0
  57. data/lib/action_view/helpers/number_helper.rb +4 -3
  58. data/lib/action_view/helpers/pagination_helper.rb +42 -27
  59. data/lib/action_view/helpers/tag_helper.rb +25 -11
  60. data/lib/action_view/helpers/text_helper.rb +119 -13
  61. data/lib/action_view/helpers/upload_progress_helper.rb +2 -2
  62. data/lib/action_view/helpers/url_helper.rb +68 -21
  63. data/lib/action_view/partials.rb +17 -6
  64. data/lib/action_view/template_error.rb +19 -24
  65. data/rakefile +4 -3
  66. data/test/abstract_unit.rb +2 -1
  67. data/test/controller/action_pack_assertions_test.rb +62 -2
  68. data/test/controller/active_record_assertions_test.rb +5 -6
  69. data/test/controller/active_record_store_test.rb +23 -1
  70. data/test/controller/addresses_render_test.rb +4 -0
  71. data/test/controller/{base_tests.rb → base_test.rb} +4 -3
  72. data/test/controller/benchmark_test.rb +36 -0
  73. data/test/controller/caching_filestore.rb +22 -40
  74. data/test/controller/capture_test.rb +10 -1
  75. data/test/controller/cgi_test.rb +145 -23
  76. data/test/controller/components_test.rb +50 -0
  77. data/test/controller/custom_handler_test.rb +3 -3
  78. data/test/controller/fake_controllers.rb +24 -0
  79. data/test/controller/filters_test.rb +6 -6
  80. data/test/controller/flash_test.rb +6 -6
  81. data/test/controller/fragment_store_setting_test.rb +45 -0
  82. data/test/controller/helper_test.rb +1 -3
  83. data/test/controller/new_render_test.rb +119 -7
  84. data/test/controller/redirect_test.rb +11 -1
  85. data/test/controller/render_test.rb +34 -1
  86. data/test/controller/request_test.rb +14 -5
  87. data/test/controller/routing_test.rb +238 -42
  88. data/test/controller/send_file_test.rb +11 -10
  89. data/test/controller/session_management_test.rb +94 -0
  90. data/test/controller/test_test.rb +194 -5
  91. data/test/controller/url_rewriter_test.rb +46 -0
  92. data/test/fixtures/layouts/talk_from_action.rhtml +2 -0
  93. data/test/fixtures/layouts/yield.rhtml +2 -0
  94. data/test/fixtures/multipart/binary_file +0 -0
  95. data/test/fixtures/multipart/large_text_file +10 -0
  96. data/test/fixtures/multipart/mixed_files +0 -0
  97. data/test/fixtures/multipart/single_parameter +5 -0
  98. data/test/fixtures/multipart/text_file +10 -0
  99. data/test/fixtures/test/_customer_greeting.rhtml +1 -0
  100. data/test/fixtures/test/_hash_object.rhtml +1 -0
  101. data/test/fixtures/test/_person.rhtml +2 -0
  102. data/test/fixtures/test/action_talk_to_layout.rhtml +2 -0
  103. data/test/fixtures/test/content_for.rhtml +2 -0
  104. data/test/fixtures/test/potential_conflicts.rhtml +4 -0
  105. data/test/template/active_record_helper_test.rb +15 -8
  106. data/test/template/asset_tag_helper_test.rb +40 -16
  107. data/test/template/compiled_templates_tests.rb +63 -0
  108. data/test/template/date_helper_test.rb +80 -4
  109. data/test/template/form_helper_test.rb +48 -42
  110. data/test/template/form_options_helper_test.rb +40 -40
  111. data/test/template/form_tag_helper_test.rb +21 -15
  112. data/test/template/java_script_macros_helper_test.rb +56 -0
  113. data/test/template/javascript_helper_test.rb +70 -47
  114. data/test/template/number_helper_test.rb +2 -0
  115. data/test/template/tag_helper_test.rb +9 -0
  116. data/test/template/text_helper_test.rb +146 -1
  117. data/test/template/upload_progress_helper_testx.rb +11 -147
  118. data/test/template/url_helper_test.rb +90 -22
  119. data/test/testing_sandbox.rb +26 -0
  120. metadata +37 -7
  121. data/lib/action_controller/auto_complete.rb +0 -47
  122. data/lib/action_controller/deprecated_renders_and_redirects.rb +0 -76
  123. data/lib/action_controller/session.rb +0 -14
@@ -25,6 +25,9 @@ module ActionController #:nodoc:
25
25
  end
26
26
  class MissingFile < ActionControllerError #:nodoc:
27
27
  end
28
+ class SessionOverflowError < ActionControllerError #:nodoc:
29
+ DEFAULT_MESSAGE = 'Your session data is larger than the data column in which it is to be stored. You must increase the size of your data column if you intend to store large data.'
30
+ end
28
31
  class DoubleRenderError < ActionControllerError #:nodoc:
29
32
  DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and only once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\". Finally, note that to cause a before filter to halt execution of the rest of the filter chain, the filter must return false, explicitly, so \"render(...) and return false\"."
30
33
 
@@ -43,7 +46,7 @@ module ActionController #:nodoc:
43
46
  # end
44
47
  #
45
48
  # def sign
46
- # Entry.create(@params["entry"])
49
+ # Entry.create(params[:entry])
47
50
  # redirect_to :action => "index"
48
51
  # end
49
52
  # end
@@ -80,7 +83,7 @@ module ActionController #:nodoc:
80
83
  #
81
84
  # def hello_ip
82
85
  # location = request.env["REMOTE_IP"]
83
- # render_text "Hello stranger from #{location}"
86
+ # render :text => "Hello stranger from #{location}"
84
87
  # end
85
88
  #
86
89
  # == Parameters
@@ -117,7 +120,7 @@ module ActionController #:nodoc:
117
120
  # 50kb object could lead to a 50MB memory overhead. In other words, think carefully about size and caching before resorting to the use
118
121
  # of the session.
119
122
  #
120
- # For removing objects from the session, you can either assign a single key to nil, like <tt>@session[:person] = nil</tt>, or you can
123
+ # For removing objects from the session, you can either assign a single key to nil, like <tt>session[:person] = nil</tt>, or you can
121
124
  # remove the entire session with reset_session.
122
125
  #
123
126
  # == Responses
@@ -196,7 +199,9 @@ module ActionController #:nodoc:
196
199
  # def do_something
197
200
  # redirect_to(:action => "elsewhere") and return if monkeys.nil?
198
201
  # render :action => "overthere" # won't be called unless monkeys is nil
199
- # end # == Environments
202
+ # end
203
+ #
204
+ # == Environments
200
205
  #
201
206
  # Action Controller works out of the box with CGI, FastCGI, and mod_ruby. CGI and mod_ruby controllers are triggered just the same using:
202
207
  #
@@ -206,8 +211,6 @@ module ActionController #:nodoc:
206
211
  #
207
212
  # FCGI.each_cgi{ |cgi| WeblogController.process_cgi(cgi) }
208
213
  class Base
209
- include ClassInheritableAttributes
210
-
211
214
  DEFAULT_RENDER_STATUS_CODE = "200 OK"
212
215
 
213
216
  # Determines whether the view has access to controller internals @request, @response, @session, and @template.
@@ -215,6 +218,10 @@ module ActionController #:nodoc:
215
218
  @@view_controller_internals = true
216
219
  cattr_accessor :view_controller_internals
217
220
 
221
+ # Protected instance variable cache
222
+ @@protected_variables_cache = nil
223
+ cattr_accessor :protected_variables_cache
224
+
218
225
  # Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets,
219
226
  # and images to a dedicated asset server away from the main web server. Example:
220
227
  # ActionController::Base.asset_host = "http://assets.example.com"
@@ -257,7 +264,7 @@ module ActionController #:nodoc:
257
264
  # <tt>request.env["REQUEST_URI"]</tt>.
258
265
  attr_accessor :request
259
266
 
260
- # Holds a hash of all the GET, POST, and Url parameters passed to the action. Accessed like <tt>@params["post_id"]</tt>
267
+ # Holds a hash of all the GET, POST, and Url parameters passed to the action. Accessed like <tt>params["post_id"]</tt>
261
268
  # to get the post_id. No type casts are made, so all values are returned as strings.
262
269
  attr_accessor :params
263
270
 
@@ -350,13 +357,14 @@ module ActionController #:nodoc:
350
357
  initialize_template_class(response)
351
358
  assign_shortcuts(request, response)
352
359
  initialize_current_url
353
- @action_name = params[:action] || 'index'
360
+ @action_name = params['action'] || 'index'
361
+ @variables_added = nil
354
362
 
355
- log_processing unless logger.nil?
363
+ log_processing if logger
356
364
  send(method, *arguments)
357
365
  close_session
358
366
 
359
- return @response
367
+ @response
360
368
  end
361
369
 
362
370
  # Returns a URL that has been rewritten according to the options hash and the defined Routes.
@@ -420,19 +428,14 @@ module ActionController #:nodoc:
420
428
  #
421
429
  # url_for :controller => 'posts', :action => nil
422
430
  #
423
- # Instead of passing an options hash, you can also pass a method reference in the form of a symbol. Consider this example:
424
- #
425
- # class WeblogController < ActionController::Base
426
- # def update
427
- # # do some update
428
- # redirect_to :dashboard_url
429
- # end
430
- #
431
- # protected
432
- # def dashboard_url
433
- # url_for :controller => (@project.active? ? "project" : "account"), :action => "dashboard"
434
- # end
435
- # end
431
+ # If you explicitly want to create a URL that's almost the same as the current URL, you can do so using the
432
+ # :overwrite_params options. Say for your posts you have different views for showing and printing them.
433
+ # Then, in the show view, you get the URL for the print view like this
434
+ #
435
+ # url_for :overwrite_params => { :action => 'print' }
436
+ #
437
+ # This takes the current URL as is and only exchanges the action. In contrast, <tt>url_for :action => 'print'</tt>
438
+ # would have slashed-off the path components are the changed action.
436
439
  def url_for(options = {}, *parameters_for_method_reference) #:doc:
437
440
  case options
438
441
  when String then options
@@ -469,7 +472,7 @@ module ActionController #:nodoc:
469
472
  #
470
473
  # # Renders the template for the action "long_goal" within the current controller,
471
474
  # # but with a custom layout
472
- # render :action => "short_goal", :layout => "spectacular"
475
+ # render :action => "long_goal", :layout => "spectacular"
473
476
  #
474
477
  # _Deprecation_ _notice_: This used to have the signatures <tt>render_action("action", status = 200)</tt>,
475
478
  # <tt>render_without_layout("controller/action", status = 200)</tt>, and
@@ -503,19 +506,24 @@ module ActionController #:nodoc:
503
506
  # <tt>render_partial(partial_path = default_template_name, object = nil, local_assigns = {})</tt> and
504
507
  # <tt>render_partial_collection(partial_name, collection, partial_spacer_template = nil, local_assigns = {})</tt>.
505
508
  #
506
- # === Rendering a file
509
+ # === Rendering a template
507
510
  #
508
- # File rendering works just like action rendering except that it takes a path relative to the template root or an absolute
509
- # path if use_full_path is passed as true. The current layout is not applied automatically.
511
+ # Template rendering works just like action rendering except that it takes a path relative to the template root.
512
+ # The current layout is automatically applied.
510
513
  #
511
514
  # # Renders the template located in [TEMPLATE_ROOT]/weblog/show.r(html|xml) (in Rails, app/views/weblog/show.rhtml)
512
- # render :file => "weblog/show"
515
+ # render :template => "weblog/show"
516
+ #
517
+ # === Rendering a file
518
+ #
519
+ # File rendering works just like action rendering except that it takes an absolute path.
520
+ # The current layout is not applied automatically.
513
521
  #
514
522
  # # Renders the template located in /path/to/some/template.r(html|xml)
515
- # render :file => "/path/to/some/template", :use_full_path => false
523
+ # render :file => "/path/to/some/template"
516
524
  #
517
525
  # # Renders the same template within the current layout, but with a 404 status code
518
- # render :file => "/path/to/some/template", :use_full_path => false, :layout => true, :status => 404
526
+ # render :file => "/path/to/some/template", :layout => true, :status => 404
519
527
  #
520
528
  # _Deprecation_ _notice_: This used to have the signature <tt>render_file(path, status = 200)</tt>
521
529
  #
@@ -559,86 +567,115 @@ module ActionController #:nodoc:
559
567
  # === Rendering nothing
560
568
  #
561
569
  # Rendering nothing is often convenient in combination with Ajax calls that perform their effect client-side or
562
- # when you just want to communicate a status code.
570
+ # when you just want to communicate a status code. Due to a bug in Safari, nothing actually means a single space.
563
571
  #
564
572
  # # Renders an empty response with status code 200
565
573
  # render :nothing => true
566
574
  #
567
575
  # # Renders an empty response with status code 401 (access denied)
568
576
  # render :nothing => true, :status => 401
569
- def render(options = {}, deprecated_status = nil) #:doc:
570
- # puts "Rendering: #{options.inspect}"
571
- raise DoubleRenderError if performed?
577
+ def render(options = nil, deprecated_status = nil) #:doc:
578
+ raise DoubleRenderError, "Can only render or redirect once per action" if performed?
572
579
 
573
580
  # Backwards compatibility
574
- return render({ :template => options || default_template_name, :status => deprecated_status }) if !options.is_a?(Hash)
581
+ unless options.is_a?(Hash)
582
+ return render_file(options || default_template_name, deprecated_status, true)
583
+ end
575
584
 
576
- add_variables_to_assigns
577
- options[:status] = (options[:status] || DEFAULT_RENDER_STATUS_CODE).to_s
578
-
579
- if options[:text]
580
- @response.headers["Status"] = options[:status]
581
- @response.body = options[:text]
582
- @performed_render = true
583
- return options[:text]
584
-
585
- elsif options[:file]
586
- assert_existance_of_template_file(options[:file]) if options[:use_full_path]
587
- logger.info("Rendering #{options[:file]} (#{options[:status]})") unless logger.nil?
588
- render(options.merge({ :text => @template.render_file(options[:file], options[:use_full_path])}))
589
-
590
- elsif options[:template]
591
- render(options.merge({ :file => options[:template], :use_full_path => true }))
592
-
593
- elsif options[:inline]
594
- render(options.merge({
595
- :text =>
596
- @template.render_template(
597
- options[:type] || :rhtml,
598
- options[:inline],
599
- options[:locals] || {}
600
- )
601
- }))
602
-
603
- elsif options[:action]
604
- render(options.merge({ :template => default_template_name(options[:action]) }))
605
-
606
- elsif options[:partial] && options[:collection]
607
- render(options.merge({
608
- :text => (
609
- @template.render_partial_collection(
610
- options[:partial] == true ? default_template_name : options[:partial],
611
- options[:collection], options[:spacer_template],
612
- options[:locals] || {}
613
- ) || ''
614
- )
615
- }))
616
-
617
- elsif options[:partial]
618
- render(options.merge({ :text => @template.render_partial(
619
- options[:partial] == true ? default_template_name : options[:partial],
620
- options[:object], options[:locals] || {}
621
- ) }))
622
-
623
- elsif options[:nothing]
624
- render(options.merge({ :text => "" }))
585
+ if text = options[:text]
586
+ render_text(text, options[:status])
625
587
 
626
588
  else
627
- render(options.merge({ :action => action_name }))
589
+ if file = options[:file]
590
+ render_file(file, options[:status], options[:use_full_path])
591
+
592
+ elsif template = options[:template]
593
+ render_file(template, options[:status], true)
594
+
595
+ elsif inline = options[:inline]
596
+ render_template(inline, options[:status], options[:type], options[:locals] || {})
597
+
598
+ elsif action_name = options[:action]
599
+ render_action(action_name, options[:status], options[:layout])
600
+
601
+ elsif partial = options[:partial]
602
+ partial = default_template_name if partial == true
603
+ if collection = options[:collection]
604
+ render_partial_collection(partial, collection, options[:spacer_template], options[:locals], options[:status])
605
+ else
606
+ render_partial(partial, ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals], options[:status])
607
+ end
608
+
609
+ elsif options[:nothing]
610
+ # Safari doesn't pass the headers of the return if the response is zero length
611
+ render_text(" ", options[:status])
612
+
613
+ else
614
+ render_file(default_template_name, options[:status], true)
615
+
616
+ end
628
617
  end
629
618
  end
630
619
 
631
620
  # Renders according to the same rules as <tt>render</tt>, but returns the result in a string instead
632
621
  # of sending it as the response body to the browser.
633
- def render_to_string(options = {}) #:doc:
622
+ def render_to_string(options = nil) #:doc:
634
623
  result = render(options)
635
624
  erase_render_results
636
- return result
625
+ result
626
+ end
627
+
628
+ def render_action(action_name, status = nil, with_layout = true)
629
+ if with_layout
630
+ render_with_layout(default_template_name(action_name), status)
631
+ else
632
+ render_with_no_layout(default_template_name(action_name), status)
633
+ end
634
+ end
635
+
636
+ def render_file(template_path, status = nil, use_full_path = false)
637
+ add_variables_to_assigns
638
+ assert_existance_of_template_file(template_path) if use_full_path
639
+ logger.info("Rendering #{template_path}" + (status ? " (#{status})" : '')) if logger
640
+ render_text(@template.render_file(template_path, use_full_path), status)
641
+ end
642
+
643
+ def render_template(template, status = nil, type = :rhtml, local_assigns = {})
644
+ add_variables_to_assigns
645
+ render_text(@template.render_template(type, template, nil, local_assigns), status)
646
+ end
647
+
648
+ def render_text(text = nil, status = nil)
649
+ @performed_render = true
650
+ @response.headers['Status'] = (status || DEFAULT_RENDER_STATUS_CODE).to_s
651
+ @response.body = text
637
652
  end
638
-
653
+
654
+ def render_nothing(status = nil)
655
+ render_text(' ', status)
656
+ end
657
+
658
+ def render_partial(partial_path = default_template_name, object = nil, local_assigns = nil, status = nil)
659
+ add_variables_to_assigns
660
+ render_text(@template.render_partial(partial_path, object, local_assigns), status)
661
+ end
662
+
663
+ def render_partial_collection(partial_name, collection, partial_spacer_template = nil, local_assigns = nil, status = nil)
664
+ add_variables_to_assigns
665
+ render_text(@template.render_partial_collection(partial_name, collection, partial_spacer_template, local_assigns), status)
666
+ end
667
+
668
+ def render_with_layout(template_name = default_template_name, status = nil, layout = nil)
669
+ render_with_a_layout(template_name, status, layout)
670
+ end
671
+
672
+ def render_without_layout(template_name = default_template_name, status = nil)
673
+ render_with_no_layout(template_name, status)
674
+ end
675
+
639
676
 
640
677
  # Clears the rendered results, allowing for another render to be performed.
641
- def erase_render_results #:nodoc:
678
+ def erase_render_results
642
679
  @response.body = nil
643
680
  @performed_render = false
644
681
  end
@@ -647,7 +684,7 @@ module ActionController #:nodoc:
647
684
  # the URL that was used to redirect or nil if there was no redirected URL
648
685
  # Note that +redirect_to+ will change the body of the response to indicate a redirection.
649
686
  # The response body is not reset here, see +erase_render_results+
650
- def erase_redirect_results #:nodoc:
687
+ def erase_redirect_results
651
688
  @performed_redirect = false
652
689
  response.redirected_to = nil
653
690
  response.redirected_to_method_params = nil
@@ -655,6 +692,11 @@ module ActionController #:nodoc:
655
692
  response.headers.delete('location')
656
693
  end
657
694
 
695
+ # Erase both render and redirect results
696
+ def erase_results
697
+ erase_render_results
698
+ erase_redirect_results
699
+ end
658
700
 
659
701
  def rewrite_options(options)
660
702
  if defaults = default_url_options(options)
@@ -711,6 +753,29 @@ module ActionController #:nodoc:
711
753
  end
712
754
  end
713
755
  end
756
+
757
+ # Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a "private" instruction, so that
758
+ # intermediate caches shouldn't cache the response.
759
+ #
760
+ # Examples:
761
+ # expires_in 20.minutes
762
+ # expires_in 3.hours, :private => false
763
+ # expires in 3.hours, 'max-stale' => 5.hours, :private => nil, :public => true
764
+ #
765
+ # This method will overwrite an existing Cache-Control header.
766
+ # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
767
+ def expires_in(seconds, options = {}) #:doc:
768
+ cache_options = { 'max-age' => seconds, 'private' => true }.symbolize_keys.merge!(options.symbolize_keys)
769
+ cache_options.delete_if { |k,v| v.nil? or v == false }
770
+ cache_control = cache_options.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"}
771
+ @response.headers["Cache-Control"] = cache_control.join(', ')
772
+ end
773
+
774
+ # Sets a HTTP 1.1 Cache-Control header of "no-cache" so no caching should occur by the browser or
775
+ # intermediate caches (like caching proxy servers).
776
+ def expires_now #:doc:
777
+ @response.headers["Cache-Control"] = "no-cache"
778
+ end
714
779
 
715
780
  # Resets the session by clearing out all the objects stored within and initializing a new session object.
716
781
  def reset_session #:doc:
@@ -720,13 +785,23 @@ module ActionController #:nodoc:
720
785
  end
721
786
 
722
787
  private
723
- def initialize_template_class(response)
724
- begin
725
- response.template = template_class.new(template_root, {}, self)
726
- rescue
727
- raise "You must assign a template class through ActionController.template_class= before processing a request"
788
+ def self.view_class
789
+ unless @view_class
790
+ # create a new class based on the default template class and include helper methods
791
+ @view_class = Class.new(ActionView::Base)
792
+ @view_class.send(:include, master_helper_module)
728
793
  end
794
+ @view_class
795
+ end
796
+
797
+ def self.view_root
798
+ @view_root ||= template_root
799
+ end
800
+
801
+ def initialize_template_class(response)
802
+ raise "You must assign a template class through ActionController.template_class= before processing a request" unless @@template_class
729
803
 
804
+ response.template = self.class.view_class.new(self.class.view_root, {}, self)
730
805
  @performed_render = @performed_redirect = false
731
806
  end
732
807
 
@@ -747,12 +822,12 @@ module ActionController #:nodoc:
747
822
  end
748
823
 
749
824
  def log_processing
750
- logger.info "\n\nProcessing #{controller_class_name}\##{action_name} (for #{request_origin})"
825
+ logger.info "\n\nProcessing #{controller_class_name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
751
826
  logger.info " Parameters: #{@params.inspect}"
752
827
  end
753
828
 
754
829
  def perform_action
755
- if action_methods.include?(action_name) || action_methods.include?('method_missing')
830
+ if self.class.action_methods.include?(action_name) || self.class.action_methods.include?('method_missing')
756
831
  send(action_name)
757
832
  render unless performed?
758
833
  elsif template_exists? && template_public?
@@ -767,17 +842,24 @@ module ActionController #:nodoc:
767
842
  end
768
843
 
769
844
  def action_methods
770
- @action_methods ||= (self.class.public_instance_methods - self.class.hidden_actions)
845
+ self.class.action_methods
771
846
  end
772
847
 
848
+ def self.action_methods
849
+ #puts "action method: #{public_instance_methods.inspect}"
850
+ @action_methods ||= (public_instance_methods - hidden_actions).inject({}) { |h, k| h[k] = true; h }
851
+ end
773
852
 
774
853
  def add_variables_to_assigns
775
- add_instance_variables_to_assigns
776
- add_class_variables_to_assigns if view_controller_internals
854
+ unless @variables_added
855
+ add_instance_variables_to_assigns
856
+ add_class_variables_to_assigns if view_controller_internals
857
+ @variables_added = true
858
+ end
777
859
  end
778
860
 
779
861
  def add_instance_variables_to_assigns
780
- @@protected_variables_cache = protected_instance_variables.inject({}) { |h, k| h[k] = true; h }
862
+ @@protected_variables_cache ||= protected_instance_variables.inject({}) { |h, k| h[k] = true; h }
781
863
  instance_variables.each do |var|
782
864
  next if @@protected_variables_cache.include?(var)
783
865
  @assigns[var[1..-1]] = instance_variable_get(var)
@@ -800,7 +882,7 @@ module ActionController #:nodoc:
800
882
 
801
883
 
802
884
  def request_origin
803
- "#{@request.remote_ip} at #{Time.now.to_s}"
885
+ "#{@request.remote_ip} at #{Time.now.to_s(:db)}"
804
886
  end
805
887
 
806
888
  def complete_request_uri