Skip to content
This repository
Browse code

Add render :update for inline RJS

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3441 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit 06dd1f2ca3398b978bb286688aa68acacd7dd712 1 parent f9c13e6
Sam Stephenson sstephenson authored
10 actionpack/CHANGELOG
... ... @@ -1,5 +1,15 @@
1 1 *SVN*
2 2
  3 +* Add render :update for inline RJS. [Sam Stephenson] Example:
  4 + class UserController < ApplicationController
  5 + def refresh
  6 + render :update do |page|
  7 + page.replace_html 'user_list', :partial => 'user', :collection => @users
  8 + page.visual_effect :highlight, 'user_list'
  9 + end
  10 + end
  11 + end
  12 +
3 13 * allow nil objects for error_messages_for [Michael Koziarski]
4 14
5 15 * Refactor human_size to exclude decimal place if it is zero. [Marcel Molina Jr.]
37 actionpack/lib/action_controller/base.rb
@@ -368,9 +368,9 @@ def process(request, response, method = :perform_action, *arguments) #:nodoc:
368 368
369 369 # Returns a URL that has been rewritten according to the options hash and the defined Routes.
370 370 # (For doing a complete redirect, use redirect_to).
371   - #
  371 + #  
372 372 # <tt>url_for</tt> is used to:
373   - #
  373 + #  
374 374 # All keys given to url_for are forwarded to the Route module, save for the following:
375 375 # * <tt>:anchor</tt> -- specifies the anchor name to be appended to the path. For example,
376 376 # <tt>url_for :controller => 'posts', :action => 'show', :id => 10, :anchor => 'comments'</tt>
@@ -386,7 +386,7 @@ def process(request, response, method = :perform_action, *arguments) #:nodoc:
386 386 #
387 387 # The default Routes setup supports a typical Rails path of "controller/action/id" where action and id are optional, with
388 388 # action defaulting to 'index' when not given. Here are some typical url_for statements and their corresponding URLs:
389   - #
  389 + #  
390 390 # url_for :controller => 'posts', :action => 'recent' # => 'proto://host.com/posts/recent'
391 391 # url_for :controller => 'posts', :action => 'index' # => 'proto://host.com/posts'
392 392 # url_for :controller => 'posts', :action => 'show', :id => 10 # => 'proto://host.com/posts/show/10'
@@ -395,7 +395,7 @@ def process(request, response, method = :perform_action, *arguments) #:nodoc:
395 395 # <tt>url_for :action => 'some_action'</tt> will retain the current controller, as expected. This behavior extends to
396 396 # other parameters, including <tt>:controller</tt>, <tt>:id</tt>, and any other parameters that are placed into a Route's
397 397 # path.
398   - #
  398 + #  
399 399 # The URL helpers such as <tt>url_for</tt> have a limited form of memory: when generating a new URL, they can look for
400 400 # missing values in the current request's parameters. Routes attempts to guess when a value should and should not be
401 401 # taken from the defaults. There are a few simple rules on how this is performed:
@@ -418,7 +418,7 @@ def process(request, response, method = :perform_action, *arguments) #:nodoc:
418 418 # answer has to do with the order in which the parameters appear in the generated path. In a nutshell, since the
419 419 # value that appears in the slot for <tt>:first</tt> is not equal to default value for <tt>:first</tt> we stop using
420 420 # defaults. On it's own, this rule can account for much of the typical Rails URL behavior.
421   - #
  421 + #  
422 422 # Although a convienence, defaults can occasionaly get in your way. In some cases a default persists longer than desired.
423 423 # The default may be cleared by adding <tt>:name => nil</tt> to <tt>url_for</tt>'s options.
424 424 # This is often required when writing form helpers, since the defaults in play may vary greatly depending upon where the
@@ -571,6 +571,16 @@ def session_enabled?
571 571 #
572 572 # _Deprecation_ _notice_: This used to have the signature <tt>render_template(template, status = 200, type = :rhtml)</tt>
573 573 #
  574 + # === Rendering inline JavaScriptGenerator page updates
  575 + #
  576 + # In addition to rendering JavaScriptGenerator page updates with Ajax in RJS templates (see ActionView::Base for details),
  577 + # you can also pass the <tt>:update</tt> parameter to +render+, along with a block, to render page updates inline.
  578 + #
  579 + # render :update do |page|
  580 + # page.replace_html 'user_list', :partial => 'user', :collection => @users
  581 + # page.visual_effect :highlight, 'user_list'
  582 + # end
  583 + #
574 584 # === Rendering nothing
575 585 #
576 586 # Rendering nothing is often convenient in combination with Ajax calls that perform their effect client-side or
@@ -581,12 +591,16 @@ def session_enabled?
581 591 #
582 592 # # Renders an empty response with status code 401 (access denied)
583 593 # render :nothing => true, :status => 401
584   - def render(options = nil, deprecated_status = nil) #:doc:
  594 + def render(options = nil, deprecated_status = nil, &block) #:doc:
585 595 raise DoubleRenderError, "Can only render or redirect once per action" if performed?
586 596
587 597 # Backwards compatibility
588 598 unless options.is_a?(Hash)
589   - return render_file(options || default_template_name, deprecated_status, true)
  599 + if options == :update
  600 + options = {:update => true}
  601 + else
  602 + return render_file(options || default_template_name, deprecated_status, true)
  603 + end
590 604 end
591 605
592 606 if text = options[:text]
@@ -613,6 +627,10 @@ def render(options = nil, deprecated_status = nil) #:doc:
613 627 render_partial(partial, ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals], options[:status])
614 628 end
615 629
  630 + elsif options[:update]
  631 + generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
  632 + render_javascript(generator.to_s)
  633 +
616 634 elsif options[:nothing]
617 635 # Safari doesn't pass the headers of the return if the response is zero length
618 636 render_text(" ", options[:status])
@@ -661,6 +679,11 @@ def render_text(text = nil, status = nil)
661 679 @response.body = text
662 680 end
663 681
  682 + def render_javascript(javascript, status = nil)
  683 + @response.headers['Content-type'] = 'text/javascript'
  684 + render_text(javascript, status)
  685 + end
  686 +
664 687 def render_nothing(status = nil)
665 688 render_text(' ', status)
666 689 end
6 actionpack/lib/action_controller/benchmarking.rb
@@ -43,14 +43,14 @@ def silence
43 43 end
44 44 end
45 45
46   - def render_with_benchmark(options = nil, deprecated_status = nil)
  46 + def render_with_benchmark(options = nil, deprecated_status = nil, &block)
47 47 unless logger
48   - render_without_benchmark(options, deprecated_status)
  48 + render_without_benchmark(options, deprecated_status, &block)
49 49 else
50 50 db_runtime = ActiveRecord::Base.connection.reset_runtime if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
51 51
52 52 render_output = nil
53   - @rendering_runtime = Benchmark::measure{ render_output = render_without_benchmark(options, deprecated_status) }.real
  53 + @rendering_runtime = Benchmark::measure{ render_output = render_without_benchmark(options, deprecated_status, &block) }.real
54 54
55 55 if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
56 56 @db_rt_before_render = db_runtime
8 actionpack/lib/action_controller/layout.rb
@@ -211,7 +211,7 @@ def active_layout(passed_layout = nil)
211 211 active_layout.include?('/') && !nested_controller ? active_layout : "layouts/#{active_layout}" if active_layout
212 212 end
213 213
214   - def render_with_a_layout(options = nil, deprecated_status = nil, deprecated_layout = nil) #:nodoc:
  214 + def render_with_a_layout(options = nil, deprecated_status = nil, deprecated_layout = nil, &block) #:nodoc:
215 215 template_with_options = options.is_a?(Hash)
216 216
217 217 if apply_layout?(template_with_options, options) && (layout = pick_layout(template_with_options, options, deprecated_layout))
@@ -219,10 +219,10 @@ def render_with_a_layout(options = nil, deprecated_status = nil, deprecated_layo
219 219 logger.info("Rendering #{options} within #{layout}") if logger
220 220
221 221 if template_with_options
222   - content_for_layout = render_with_no_layout(options)
  222 + content_for_layout = render_with_no_layout(options, &block)
223 223 deprecated_status = options[:status] || deprecated_status
224 224 else
225   - content_for_layout = render_with_no_layout(options, deprecated_status)
  225 + content_for_layout = render_with_no_layout(options, deprecated_status, &block)
226 226 end
227 227
228 228 erase_render_results
@@ -230,7 +230,7 @@ def render_with_a_layout(options = nil, deprecated_status = nil, deprecated_layo
230 230 @template.instance_variable_set("@content_for_layout", content_for_layout)
231 231 render_text(@template.render_file(layout, true), deprecated_status)
232 232 else
233   - render_with_no_layout(options, deprecated_status)
  233 + render_with_no_layout(options, deprecated_status, &block)
234 234 end
235 235 end
236 236
13 actionpack/test/controller/new_render_test.rb
@@ -188,6 +188,13 @@ def render_js_with_explicit_action_template
188 188 render :action => 'delete_with_js'
189 189 end
190 190
  191 + def update_page
  192 + render :update do |page|
  193 + page.replace_html 'balance', '$37,000,000.00'
  194 + page.visual_effect :highlight, 'balance'
  195 + end
  196 + end
  197 +
191 198 def action_talk_to_layout
192 199 # Action template sets variable that's picked up by layout
193 200 end
@@ -480,6 +487,12 @@ def test_render_text_with_assigns
480 487 assert_equal "world", assigns["hello"]
481 488 end
482 489
  490 + def test_update_page
  491 + get :update_page
  492 + assert_equal 'text/javascript', @response.headers['Content-type']
  493 + assert_equal 2, @response.body.split($/).length
  494 + end
  495 +
483 496 def test_yield_content_for
484 497 get :yield_content_for
485 498 assert_equal "<title>Putting stuff in the title!</title>\n\nGreat stuff!\n", @response.body

0 comments on commit 06dd1f2

Please sign in to comment.
Something went wrong with that request. Please try again.