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
@@ -85,8 +85,9 @@ module Test #:nodoc:
85
85
  assert_equal(eurl, url, msg) if eurl && url
86
86
  assert_equal(epath, path, msg) if epath && path
87
87
  else
88
- msg = build_message(message, "response is not a redirection to all of the options supplied (redirection is <?>)",
89
- @response.redirected_to || @response.redirect_url)
88
+ @response_diff = options.diff(@response.redirected_to) if options.is_a?(Hash) && @response.redirected_to.is_a?(Hash)
89
+ msg = build_message(message, "response is not a redirection to all of the options supplied (redirection is <?>)#{', difference: <?>' if @response_diff}",
90
+ @response.redirected_to || @response.redirect_url, @response_diff)
90
91
 
91
92
  assert_block(msg) do
92
93
  if options.is_a?(Symbol)
@@ -302,19 +303,17 @@ module Test #:nodoc:
302
303
  end
303
304
 
304
305
  # ensures that the passed record is valid by active record standards. returns the error messages if not
305
- def assert_valid(record)
306
+ def assert_valid(record)
306
307
  clean_backtrace do
307
- assert record.valid?, record.errors.full_messages
308
+ assert record.valid?, record.errors.full_messages.join("\n")
308
309
  end
309
310
  end
310
311
 
311
312
  def clean_backtrace(&block)
312
- begin
313
- yield
314
- rescue AssertionFailedError => e
315
- path = File.expand_path(__FILE__)
316
- raise AssertionFailedError, e.message, e.backtrace.reject { |line| File.expand_path(line) =~ /#{path}/ }
317
- end
313
+ yield
314
+ rescue AssertionFailedError => e
315
+ path = File.expand_path(__FILE__)
316
+ raise AssertionFailedError, e.message, e.backtrace.reject { |line| File.expand_path(line) =~ /#{path}/ }
318
317
  end
319
318
  end
320
319
  end
@@ -1,3 +1,4 @@
1
+ require 'action_controller/mime_type'
1
2
  require 'action_controller/request'
2
3
  require 'action_controller/response'
3
4
  require 'action_controller/routing'
@@ -40,6 +41,13 @@ module ActionController #:nodoc:
40
41
  super(message || DEFAULT_MESSAGE)
41
42
  end
42
43
  end
44
+ class RedirectBackError < ActionControllerError #:nodoc:
45
+ DEFAULT_MESSAGE = 'No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify @request.env["HTTP_REFERER"].'
46
+
47
+ def initialize(message = nil)
48
+ super(message || DEFAULT_MESSAGE)
49
+ end
50
+ end
43
51
 
44
52
  # Action Controllers are made up of one or more actions that performs its purpose and then either renders a template or
45
53
  # redirects to another action. An action is defined as a public method on the controller, which will automatically be
@@ -217,7 +225,9 @@ module ActionController #:nodoc:
217
225
  # FCGI.each_cgi{ |cgi| WeblogController.process_cgi(cgi) }
218
226
  class Base
219
227
  DEFAULT_RENDER_STATUS_CODE = "200 OK"
220
-
228
+
229
+ include Reloadable::Subclasses
230
+
221
231
  # Determines whether the view has access to controller internals @request, @response, @session, and @template.
222
232
  # By default, it does.
223
233
  @@view_controller_internals = true
@@ -251,10 +261,37 @@ module ActionController #:nodoc:
251
261
  @@allow_concurrency = false
252
262
  cattr_accessor :allow_concurrency
253
263
 
264
+ # Modern REST web services often need to submit complex data to the web application.
265
+ # The param_parsers hash lets you register handlers wich will process the http body and add parameters to the
266
+ # @params hash. These handlers are invoked for post and put requests.
267
+ #
268
+ # By default application/xml and application/x-yaml are enabled. For application/xml, a XmlSimple class with
269
+ # the same param name as the root will be instanciated in the @params. This allows XML requests to mask themselves
270
+ # as regular form submissions, so you can have one action serve both regular forms and web service requests. For
271
+ # application/x-yaml, the YAML document is merged into the parameters and appears to the application as if the
272
+ # YAML elements were simply form submissions.
273
+ #
274
+ # Example of doing your own parser for a custom content type:
275
+ #
276
+ # ActionController::Base.param_parsers[Mime::Type.lookup('application/atom+xml')] = Proc.new do |data|
277
+ # node = REXML::Document.new(post)
278
+ # { node.root.name => node.root }
279
+ # end
280
+ #
281
+ # Note: Up until release 1.1 of Rails, Action Controller would default to using XmlSimple configured to discard the
282
+ # root node for such requests. The new default is to keep the root, such that "<r><name>David</name></r>" results
283
+ # in params[:r][:name] for "David" instead of params[:name]. To get the old behavior, you can
284
+ # re-register XmlSimple as application/xml handler ike this:
285
+ #
286
+ # ActionController::Base.param_parsers[Mime::XML] =
287
+ # Proc.new { |data| XmlSimple.xml_in(data, 'ForceArray' => false) }
288
+ @@param_parsers = { Mime::XML => :xml_simple, Mime::YAML => :yaml }
289
+ cattr_accessor :param_parsers
290
+
254
291
  # Template root determines the base from which template references will be made. So a call to render("test/template")
255
292
  # will be converted to "#{template_root}/test/template.rhtml".
256
293
  class_inheritable_accessor :template_root
257
-
294
+
258
295
  # The logger is used for generating information on the action run-time (including benchmarking) if available.
259
296
  # Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
260
297
  cattr_accessor :logger
@@ -293,7 +330,7 @@ module ActionController #:nodoc:
293
330
 
294
331
  # Returns the name of the action this controller is processing.
295
332
  attr_accessor :action_name
296
-
333
+
297
334
  class << self
298
335
  # Factory for the standard create, process loop where the controller is discarded after processing.
299
336
  def process(request, response) #:nodoc:
@@ -312,19 +349,12 @@ module ActionController #:nodoc:
312
349
 
313
350
  # Converts the class name from something like "OneModule::TwoModule::NeatController" to "one_module/two_module/neat".
314
351
  def controller_path
315
- unless @controller_path
316
- components = self.name.to_s.split('::')
317
- components[-1] = $1 if /^(.*)Controller$/ =~ components.last
318
- # Accomodate the root Controllers module.
319
- components.shift if components.first == 'Controllers'
320
- @controller_path = components.map { |name| name.underscore }.join('/')
321
- end
322
- @controller_path
352
+ @controller_path ||= name.gsub(/Controller$/, '').underscore
323
353
  end
324
354
 
325
355
  # Return an array containing the names of public methods that have been marked hidden from the action processor.
326
356
  # By default, all methods defined in ActionController::Base and included modules are hidden.
327
- # More methods can be hidden using +hide_actions+.
357
+ # More methods can be hidden using <tt>hide_actions</tt>.
328
358
  def hidden_actions
329
359
  write_inheritable_attribute(:hidden_actions, ActionController::Base.public_instance_methods) unless read_inheritable_attribute(:hidden_actions)
330
360
  read_inheritable_attribute(:hidden_actions)
@@ -332,51 +362,32 @@ module ActionController #:nodoc:
332
362
 
333
363
  # Hide each of the given methods from being callable as actions.
334
364
  def hide_action(*names)
335
- write_inheritable_attribute(:hidden_actions, hidden_actions | names.collect {|n| n.to_s})
336
- end
337
-
338
- # Set the template root to be one directory behind the root dir of the controller. Examples:
339
- # /code/weblog/components/admin/users_controller.rb with Admin::UsersController
340
- # will use /code/weblog/components as template root
341
- # and find templates in /code/weblog/components/admin/users/
342
- #
343
- # /code/weblog/components/admin/parties/users_controller.rb with Admin::Parties::UsersController
344
- # will also use /code/weblog/components as template root
345
- # and find templates in /code/weblog/components/admin/parties/users/
346
- def uses_component_template_root
347
- path_of_calling_controller = File.dirname(caller[0].split(/:\d+:/).first)
348
- path_of_controller_root = path_of_calling_controller.sub(/#{controller_path.split("/")[0..-2]}$/, "") # " (for ruby-mode)
349
- self.template_root = path_of_controller_root
350
- end
351
-
352
- # Temporary method for enabling upload progress until it's ready to leave experimental mode
353
- def enable_upload_progress # :nodoc:
354
- require 'action_controller/upload_progress'
355
- include ActionController::UploadProgress
365
+ write_inheritable_attribute(:hidden_actions, hidden_actions | names.collect { |n| n.to_s })
356
366
  end
357
367
  end
358
368
 
359
- public
369
+ public
360
370
  # Extracts the action_name from the request parameters and performs that action.
361
371
  def process(request, response, method = :perform_action, *arguments) #:nodoc:
362
372
  initialize_template_class(response)
363
373
  assign_shortcuts(request, response)
364
374
  initialize_current_url
365
- @action_name = params['action'] || 'index'
366
- @variables_added = nil
367
-
368
- log_processing if logger
375
+ assign_names
376
+ forget_variables_added_to_assigns
377
+
378
+ log_processing
369
379
  send(method, *arguments)
370
- @response
380
+
381
+ response
371
382
  ensure
372
- close_session
383
+ process_cleanup
373
384
  end
374
385
 
375
386
  # Returns a URL that has been rewritten according to the options hash and the defined Routes.
376
387
  # (For doing a complete redirect, use redirect_to).
377
- #
388
+ #  
378
389
  # <tt>url_for</tt> is used to:
379
- #
390
+ #  
380
391
  # All keys given to url_for are forwarded to the Route module, save for the following:
381
392
  # * <tt>:anchor</tt> -- specifies the anchor name to be appended to the path. For example,
382
393
  # <tt>url_for :controller => 'posts', :action => 'show', :id => 10, :anchor => 'comments'</tt>
@@ -392,7 +403,7 @@ module ActionController #:nodoc:
392
403
  #
393
404
  # The default Routes setup supports a typical Rails path of "controller/action/id" where action and id are optional, with
394
405
  # action defaulting to 'index' when not given. Here are some typical url_for statements and their corresponding URLs:
395
- #
406
+ #  
396
407
  # url_for :controller => 'posts', :action => 'recent' # => 'proto://host.com/posts/recent'
397
408
  # url_for :controller => 'posts', :action => 'index' # => 'proto://host.com/posts'
398
409
  # url_for :controller => 'posts', :action => 'show', :id => 10 # => 'proto://host.com/posts/show/10'
@@ -401,7 +412,7 @@ module ActionController #:nodoc:
401
412
  # <tt>url_for :action => 'some_action'</tt> will retain the current controller, as expected. This behavior extends to
402
413
  # other parameters, including <tt>:controller</tt>, <tt>:id</tt>, and any other parameters that are placed into a Route's
403
414
  # path.
404
- #
415
+ #  
405
416
  # The URL helpers such as <tt>url_for</tt> have a limited form of memory: when generating a new URL, they can look for
406
417
  # missing values in the current request's parameters. Routes attempts to guess when a value should and should not be
407
418
  # taken from the defaults. There are a few simple rules on how this is performed:
@@ -424,7 +435,7 @@ module ActionController #:nodoc:
424
435
  # answer has to do with the order in which the parameters appear in the generated path. In a nutshell, since the
425
436
  # value that appears in the slot for <tt>:first</tt> is not equal to default value for <tt>:first</tt> we stop using
426
437
  # defaults. On it's own, this rule can account for much of the typical Rails URL behavior.
427
- #
438
+ #  
428
439
  # Although a convienence, defaults can occasionaly get in your way. In some cases a default persists longer than desired.
429
440
  # The default may be cleared by adding <tt>:name => nil</tt> to <tt>url_for</tt>'s options.
430
441
  # This is often required when writing form helpers, since the defaults in play may vary greatly depending upon where the
@@ -577,6 +588,16 @@ module ActionController #:nodoc:
577
588
  #
578
589
  # _Deprecation_ _notice_: This used to have the signature <tt>render_template(template, status = 200, type = :rhtml)</tt>
579
590
  #
591
+ # === Rendering inline JavaScriptGenerator page updates
592
+ #
593
+ # In addition to rendering JavaScriptGenerator page updates with Ajax in RJS templates (see ActionView::Base for details),
594
+ # you can also pass the <tt>:update</tt> parameter to +render+, along with a block, to render page updates inline.
595
+ #
596
+ # render :update do |page|
597
+ # page.replace_html 'user_list', :partial => 'user', :collection => @users
598
+ # page.visual_effect :highlight, 'user_list'
599
+ # end
600
+ #
580
601
  # === Rendering nothing
581
602
  #
582
603
  # Rendering nothing is often convenient in combination with Ajax calls that perform their effect client-side or
@@ -587,12 +608,20 @@ module ActionController #:nodoc:
587
608
  #
588
609
  # # Renders an empty response with status code 401 (access denied)
589
610
  # render :nothing => true, :status => 401
590
- def render(options = nil, deprecated_status = nil) #:doc:
611
+ def render(options = nil, deprecated_status = nil, &block) #:doc:
591
612
  raise DoubleRenderError, "Can only render or redirect once per action" if performed?
592
613
 
593
614
  # Backwards compatibility
594
615
  unless options.is_a?(Hash)
595
- return render_file(options || default_template_name, deprecated_status, true)
616
+ if options == :update
617
+ options = {:update => true}
618
+ else
619
+ return render_file(options || default_template_name, deprecated_status, true)
620
+ end
621
+ end
622
+
623
+ if content_type = options[:content_type]
624
+ headers["Content-Type"] = content_type
596
625
  end
597
626
 
598
627
  if text = options[:text]
@@ -610,7 +639,10 @@ module ActionController #:nodoc:
610
639
 
611
640
  elsif action_name = options[:action]
612
641
  render_action(action_name, options[:status], options[:layout])
613
-
642
+
643
+ elsif xml = options[:xml]
644
+ render_xml(xml, options[:status])
645
+
614
646
  elsif partial = options[:partial]
615
647
  partial = default_template_name if partial == true
616
648
  if collection = options[:collection]
@@ -619,6 +651,13 @@ module ActionController #:nodoc:
619
651
  render_partial(partial, ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals], options[:status])
620
652
  end
621
653
 
654
+ elsif options[:update]
655
+ add_variables_to_assigns
656
+ @template.send :evaluate_assigns
657
+
658
+ generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
659
+ render_javascript(generator.to_s)
660
+
622
661
  elsif options[:nothing]
623
662
  # Safari doesn't pass the headers of the return if the response is zero length
624
663
  render_text(" ", options[:status])
@@ -632,74 +671,87 @@ module ActionController #:nodoc:
632
671
 
633
672
  # Renders according to the same rules as <tt>render</tt>, but returns the result in a string instead
634
673
  # of sending it as the response body to the browser.
635
- def render_to_string(options = nil) #:doc:
636
- result = render(options)
674
+ def render_to_string(options = nil, &block) #:doc:
675
+ result = render(options, &block)
676
+
637
677
  erase_render_results
638
- @variables_added = nil
639
- @template.instance_variable_set("@assigns_added", nil)
678
+ forget_variables_added_to_assigns
679
+ reset_variables_added_to_assigns
680
+
640
681
  result
641
682
  end
642
683
 
643
- def render_action(action_name, status = nil, with_layout = true)
644
- if with_layout
645
- render_with_layout(default_template_name(action_name), status)
684
+ def render_action(action_name, status = nil, with_layout = true) #:nodoc:
685
+ template = default_template_name(action_name.to_s)
686
+ if with_layout && !template_exempt_from_layout?(template)
687
+ render_with_layout(template, status)
646
688
  else
647
- render_with_no_layout(default_template_name(action_name), status)
689
+ render_without_layout(template, status)
648
690
  end
649
691
  end
650
692
 
651
- def render_file(template_path, status = nil, use_full_path = false, locals = {})
693
+ def render_file(template_path, status = nil, use_full_path = false, locals = {}) #:nodoc:
652
694
  add_variables_to_assigns
653
- assert_existance_of_template_file(template_path) if use_full_path
695
+ assert_existence_of_template_file(template_path) if use_full_path
654
696
  logger.info("Rendering #{template_path}" + (status ? " (#{status})" : '')) if logger
655
697
  render_text(@template.render_file(template_path, use_full_path, locals), status)
656
698
  end
657
699
 
658
- def render_template(template, status = nil, type = :rhtml, local_assigns = {})
700
+ def render_template(template, status = nil, type = :rhtml, local_assigns = {}) #:nodoc:
659
701
  add_variables_to_assigns
660
702
  render_text(@template.render_template(type, template, nil, local_assigns), status)
661
703
  end
662
704
 
663
- def render_text(text = nil, status = nil)
705
+ def render_text(text = nil, status = nil) #:nodoc:
664
706
  @performed_render = true
665
707
  @response.headers['Status'] = (status || DEFAULT_RENDER_STATUS_CODE).to_s
666
708
  @response.body = text
667
709
  end
668
710
 
669
- def render_nothing(status = nil)
711
+ def render_javascript(javascript, status = nil) #:nodoc:
712
+ @response.headers['Content-Type'] = 'text/javascript; charset=UTF-8'
713
+ render_text(javascript, status)
714
+ end
715
+
716
+ def render_xml(xml, status = nil) #:nodoc:
717
+ @response.headers['Content-Type'] = 'application/xml'
718
+ render_text(xml, status)
719
+ end
720
+
721
+ def render_nothing(status = nil) #:nodoc:
670
722
  render_text(' ', status)
671
723
  end
672
724
 
673
- def render_partial(partial_path = default_template_name, object = nil, local_assigns = nil, status = nil)
725
+ def render_partial(partial_path = default_template_name, object = nil, local_assigns = nil, status = nil) #:nodoc:
674
726
  add_variables_to_assigns
675
727
  render_text(@template.render_partial(partial_path, object, local_assigns), status)
676
728
  end
677
729
 
678
- def render_partial_collection(partial_name, collection, partial_spacer_template = nil, local_assigns = nil, status = nil)
730
+ def render_partial_collection(partial_name, collection, partial_spacer_template = nil, local_assigns = nil, status = nil) #:nodoc:
679
731
  add_variables_to_assigns
680
732
  render_text(@template.render_partial_collection(partial_name, collection, partial_spacer_template, local_assigns), status)
681
733
  end
682
734
 
683
- def render_with_layout(template_name = default_template_name, status = nil, layout = nil)
735
+ def render_with_layout(template_name = default_template_name, status = nil, layout = nil) #:nodoc:
684
736
  render_with_a_layout(template_name, status, layout)
685
737
  end
686
738
 
687
- def render_without_layout(template_name = default_template_name, status = nil)
739
+ def render_without_layout(template_name = default_template_name, status = nil) #:nodoc:
688
740
  render_with_no_layout(template_name, status)
689
741
  end
690
742
 
691
743
 
692
744
  # Clears the rendered results, allowing for another render to be performed.
693
- def erase_render_results
745
+ def erase_render_results #:nodoc:
694
746
  @response.body = nil
695
747
  @performed_render = false
696
748
  end
697
-
749
+
698
750
  # Clears the redirected results from the headers, resets the status to 200 and returns
699
751
  # the URL that was used to redirect or nil if there was no redirected URL
700
752
  # Note that +redirect_to+ will change the body of the response to indicate a redirection.
701
753
  # The response body is not reset here, see +erase_render_results+
702
- def erase_redirect_results
754
+ def erase_redirect_results #:nodoc:
703
755
  @performed_redirect = false
704
756
  response.redirected_to = nil
705
757
  response.redirected_to_method_params = nil
@@ -708,12 +760,12 @@ module ActionController #:nodoc:
708
760
  end
709
761
 
710
762
  # Erase both render and redirect results
711
- def erase_results
763
+ def erase_results #:nodoc:
712
764
  erase_render_results
713
765
  erase_redirect_results
714
766
  end
715
767
 
716
- def rewrite_options(options)
768
+ def rewrite_options(options) #:nodoc:
717
769
  if defaults = default_url_options(options)
718
770
  defaults.merge(options)
719
771
  else
@@ -753,7 +805,7 @@ module ActionController #:nodoc:
753
805
  case options
754
806
  when %r{^\w+://.*}
755
807
  raise DoubleRenderError if performed?
756
- logger.info("Redirected to #{options}") unless logger.nil?
808
+ logger.info("Redirected to #{options}") if logger
757
809
  response.redirect(options)
758
810
  response.redirected_to = options
759
811
  @performed_redirect = true
@@ -762,7 +814,7 @@ module ActionController #:nodoc:
762
814
  redirect_to(request.protocol + request.host_with_port + options)
763
815
 
764
816
  when :back
765
- redirect_to(request.env["HTTP_REFERER"])
817
+ request.env["HTTP_REFERER"] ? redirect_to(request.env["HTTP_REFERER"]) : raise(RedirectBackError)
766
818
 
767
819
  else
768
820
  if parameters_for_method_reference.empty?
@@ -807,12 +859,11 @@ module ActionController #:nodoc:
807
859
 
808
860
  private
809
861
  def self.view_class
810
- unless @view_class
862
+ @view_class ||=
811
863
  # create a new class based on the default template class and include helper methods
812
- @view_class = Class.new(ActionView::Base)
813
- @view_class.send(:include, master_helper_module)
814
- end
815
- @view_class
864
+ returning Class.new(ActionView::Base) do |view_class|
865
+ view_class.send(:include, master_helper_module)
866
+ end
816
867
  end
817
868
 
818
869
  def self.view_root
@@ -835,7 +886,8 @@ module ActionController #:nodoc:
835
886
 
836
887
  @session = @response.session
837
888
  @template = @response.template
838
- @assigns = @response.template.assigns
889
+ @assigns = @response.template.assigns
890
+
839
891
  @headers = @response.headers
840
892
  end
841
893
 
@@ -844,8 +896,11 @@ module ActionController #:nodoc:
844
896
  end
845
897
 
846
898
  def log_processing
847
- logger.info "\n\nProcessing #{controller_class_name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
848
- logger.info " Parameters: #{@params.inspect}"
899
+ if logger
900
+ logger.info "\n\nProcessing #{controller_class_name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
901
+ logger.info " Session ID: #{@session.session_id}" if @session and @session.respond_to?(:session_id)
902
+ logger.info " Parameters: #{@params.inspect}"
903
+ end
849
904
  end
850
905
 
851
906
  def perform_action
@@ -863,6 +918,10 @@ module ActionController #:nodoc:
863
918
  @performed_render || @performed_redirect
864
919
  end
865
920
 
921
+ def assign_names
922
+ @action_name = (params['action'] || 'index')
923
+ end
924
+
866
925
  def action_methods
867
926
  self.class.action_methods
868
927
  end
@@ -878,6 +937,14 @@ module ActionController #:nodoc:
878
937
  @variables_added = true
879
938
  end
880
939
  end
940
+
941
+ def forget_variables_added_to_assigns
942
+ @variables_added = nil
943
+ end
944
+
945
+ def reset_variables_added_to_assigns
946
+ @template.instance_variable_set("@assigns_added", nil)
947
+ end
881
948
 
882
949
  def add_instance_variables_to_assigns
883
950
  @@protected_variables_cache ||= protected_instance_variables.inject({}) { |h, k| h[k] = true; h }
@@ -897,23 +964,23 @@ module ActionController #:nodoc:
897
964
  if view_controller_internals
898
965
  [ "@assigns", "@performed_redirect", "@performed_render" ]
899
966
  else
900
- [ "@assigns", "@performed_redirect", "@performed_render", "@request", "@response", "@session", "@cookies", "@template" ]
967
+ [ "@assigns", "@performed_redirect", "@performed_render", "@request", "@response", "@session", "@cookies", "@template", "@request_origin", "@parent_controller" ]
901
968
  end
902
969
  end
903
970
 
904
-
905
971
  def request_origin
906
- "#{@request.remote_ip} at #{Time.now.to_s(:db)}"
972
+ # this *needs* to be cached!
973
+ # otherwise you'd get different results if calling it more than once
974
+ @request_origin ||= "#{@request.remote_ip} at #{Time.now.to_s(:db)}"
907
975
  end
908
976
 
909
977
  def complete_request_uri
910
- request.protocol + request.host + request.request_uri
978
+ "#{@request.protocol}#{@request.host}#{@request.request_uri}"
911
979
  end
912
980
 
913
981
  def close_session
914
982
  @session.close unless @session.nil? || Hash === @session
915
983
  end
916
-
917
984
 
918
985
  def template_exists?(template_name = default_template_name)
919
986
  @template.file_exists?(template_name)
@@ -923,7 +990,11 @@ module ActionController #:nodoc:
923
990
  @template.file_public?(template_name)
924
991
  end
925
992
 
926
- def assert_existance_of_template_file(template_name)
993
+ def template_exempt_from_layout?(template_name = default_template_name)
994
+ template_name =~ /\.rjs$/ || (@template.pick_template_extension(template_name) == :rjs rescue false)
995
+ end
996
+
997
+ def assert_existence_of_template_file(template_name)
927
998
  unless template_exists?(template_name) || ignore_missing_templates
928
999
  full_template_path = @template.send(:full_template_path, template_name, 'rhtml')
929
1000
  template_type = (template_name =~ /layouts/i) ? 'layout' : 'template'
@@ -931,8 +1002,26 @@ module ActionController #:nodoc:
931
1002
  end
932
1003
  end
933
1004
 
934
- def default_template_name(default_action_name = action_name)
935
- "#{self.class.controller_path}/#{default_action_name}"
1005
+ def default_template_name(action_name = self.action_name)
1006
+ if action_name
1007
+ action_name = action_name.to_s
1008
+ if action_name.include?('/') && template_path_includes_controller?(action_name)
1009
+ action_name = strip_out_controller(action_name)
1010
+ end
1011
+ end
1012
+ "#{self.class.controller_path}/#{action_name}"
1013
+ end
1014
+
1015
+ def strip_out_controller(path)
1016
+ path.split('/', 2).last
1017
+ end
1018
+
1019
+ def template_path_includes_controller?(path)
1020
+ self.class.controller_path.split('/')[-1] == path.split('/')[0]
1021
+ end
1022
+
1023
+ def process_cleanup
1024
+ close_session
936
1025
  end
937
1026
  end
938
1027
  end