提交 eea66892 编写于 作者: X Xavier Noria

removes support for render :update

上级 25181caf
......@@ -41,7 +41,7 @@ def _handle_render_options(options)
end
# Hash of available renderers, mapping a renderer name to its proc.
# Default keys are :json, :js, :xml and :update.
# Default keys are :json, :js, :xml.
RENDERERS = {}
# Adds a new renderer to call within controller actions.
......@@ -107,12 +107,5 @@ module All
self.content_type ||= Mime::XML
self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml(options) : xml
end
add :update do |proc, options|
view_context = self.view_context
generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(view_context, &proc)
self.content_type = Mime::JS
self.response_body = generator.to_s
end
end
end
......@@ -34,13 +34,6 @@ def html()
@content = nil
end
def rjs()
render :update do |page|
@update.call page
end
@update = nil
end
def xml()
render :text=>@content, :layout=>false, :content_type=>Mime::XML
@content = nil
......@@ -219,35 +212,6 @@ def test_assert_select_text_match
end
end
# With single result.
def test_assert_select_from_rjs_with_single_result
render_rjs do |page|
page.replace_html "test", "<div id=\"1\">foo</div>\n<div id=\"2\">foo</div>"
end
assert_select "div" do |elements|
assert elements.size == 2
assert_select "#1"
assert_select "#2"
end
assert_select "div#?", /\d+/ do |elements|
assert_select "#1"
assert_select "#2"
end
end
# With multiple results.
def test_assert_select_from_rjs_with_multiple_results
render_rjs do |page|
page.replace_html "test", "<div id=\"1\">foo</div>"
page.replace_html "test2", "<div id=\"2\">foo</div>"
end
assert_select "div" do |elements|
assert elements.size == 2
assert_select "#1"
assert_select "#2"
end
end
def test_elect_with_xml_namespace_attributes
render_html %Q{<link xlink:href="http://nowhere.com"></link>}
assert_nothing_raised { assert_select "link[xlink:href=http://nowhere.com]" }
......@@ -281,28 +245,6 @@ def test_nested_css_select
end
end
# With one result.
def test_css_select_from_rjs_with_single_result
render_rjs do |page|
page.replace_html "test", "<div id=\"1\">foo</div>\n<div id=\"2\">foo</div>"
end
assert_equal 2, css_select("div").size
assert_equal 1, css_select("#1").size
assert_equal 1, css_select("#2").size
end
# With multiple results.
def test_css_select_from_rjs_with_multiple_results
render_rjs do |page|
page.replace_html "test", "<div id=\"1\">foo</div>"
page.replace_html "test2", "<div id=\"2\">foo</div>"
end
assert_equal 2, css_select("div").size
assert_equal 1, css_select("#1").size
assert_equal 1, css_select("#2").size
end
def test_feed_item_encoded
render_xml <<-EOF
<rss version="2.0">
......@@ -377,11 +319,6 @@ def render_html(html)
get :html
end
def render_rjs(&block)
@controller.response_with(&block)
get :rjs
end
def render_xml(xml)
@controller.response_with = xml
get :xml
......
require 'abstract_unit'
module RenderRjs
class BasicController < ActionController::Base
layout "application", :only => :index_respond_to
self.view_paths = [ActionView::FixtureResolver.new(
"layouts/application.html.erb" => "",
"render_rjs/basic/index.js.rjs" => "page[:customer].replace_html render(:partial => 'customer')",
"render_rjs/basic/index_html.js.rjs" => "page[:customer].replace_html :partial => 'customer'",
"render_rjs/basic/index_no_js.js.erb" => "<%= render(:partial => 'developer') %>",
"render_rjs/basic/_customer.js.erb" => "JS Partial",
"render_rjs/basic/_customer.html.erb" => "HTML Partial",
"render_rjs/basic/_developer.html.erb" => "HTML Partial",
"render_rjs/basic/index_locale.js.rjs" => "page[:customer].replace_html :partial => 'customer'",
"render_rjs/basic/_customer.da.html.erb" => "Danish HTML Partial",
"render_rjs/basic/_customer.da.js.erb" => "Danish JS Partial"
)]
def index
render
end
def index_respond_to
respond_to do |format|
format.js { render :action => "index_no_js" }
end
end
def index_locale
self.locale = :da
end
end
class TestBasic < Rack::TestCase
testing BasicController
def setup
@old_locale = I18n.locale
end
def teardown
I18n.locale = @old_locale
end
test "rendering a partial in an RJS template should pick the JS template over the HTML one" do
get :index, "format" => "js"
assert_response("$(\"customer\").update(\"JS Partial\");")
end
test "rendering a partial in an RJS template should pick the HTML one if no JS is available" do
get :index_no_js, "format" => "js"
assert_response("HTML Partial")
end
test "rendering a partial in an RJS template should pick the HTML one if no JS is available on respond_to" do
get :index_respond_to, "format" => "js"
assert_response("HTML Partial")
end
test "replacing an element with a partial in an RJS template should pick the HTML template over the JS one" do
get :index_html, "format" => "js"
assert_response("$(\"customer\").update(\"HTML Partial\");")
end
test "replacing an element with a partial in an RJS template with a locale should pick the localed HTML template" do
get :index_locale, "format" => "js"
assert_response("$(\"customer\").update(\"Danish HTML Partial\");")
end
end
end
......@@ -14,10 +14,6 @@ def render_vanilla_js_hello
render :js => "alert('hello')"
end
def greeting
# let's just rely on the template
end
def show_partial
render :partial => 'partial'
end
......@@ -31,11 +27,6 @@ def test_render_vanilla_js
assert_equal "text/javascript", @response.content_type
end
def test_render_with_default_from_accept_header
xhr :get, :greeting
assert_equal "$(\"body\").visualEffect(\"highlight\");", @response.body
end
def test_should_render_js_partial
xhr :get, :show_partial, :format => 'js'
assert_equal 'partial js', @response.body
......
require 'abstract_unit'
require 'controller/fake_models'
require 'pathname'
ActionController.add_renderer :simon do |says, options|
self.content_type = Mime::TEXT
......@@ -9,248 +7,13 @@
class RenderOtherTest < ActionController::TestCase
class TestController < ActionController::Base
protect_from_forgery
def self.controller_path
'test'
end
layout :determine_layout
module RenderTestHelper
def rjs_helper_method_from_module
page.visual_effect :highlight
end
end
helper RenderTestHelper
helper do
def rjs_helper_method(value)
page.visual_effect :highlight, value
end
end
def enum_rjs_test
render :update do |page|
page.select('.product').each do |value|
page.rjs_helper_method_from_module
page.rjs_helper_method(value)
page.sortable(value, :url => { :action => "order" })
page.draggable(value)
end
end
end
def render_explicit_html_template
end
def render_custom_code_rjs
render :update, :status => 404 do |page|
page.replace :foo, :partial => 'partial'
end
end
def render_implicit_html_template
end
def render_js_with_explicit_template
@project_id = 4
render :template => 'test/delete_with_js'
end
def render_js_with_explicit_action_template
@project_id = 4
render :action => 'delete_with_js'
end
def delete_with_js
@project_id = 4
end
def update_page
render :update do |page|
page.replace_html 'balance', '$37,000,000.00'
page.visual_effect :highlight, 'balance'
end
end
def update_page_with_instance_variables
@money = '$37,000,000.00'
@div_id = 'balance'
render :update do |page|
page.replace_html @div_id, @money
page.visual_effect :highlight, @div_id
end
end
def update_page_with_view_method
render :update do |page|
page.replace_html 'person', pluralize(2, 'person')
end
end
def partial_as_rjs
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
def respond_to_partial_as_rjs
respond_to do |format|
format.js do
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
end
end
def render_alternate_default
# For this test, the method "default_render" is overridden:
@alternate_default_render = lambda do
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
end
def render_simon_says
render :simon => "foo"
end
private
def default_render
@alternate_default_render ||= nil
if @alternate_default_render
@alternate_default_render.call
else
super
end
end
def determine_layout
case action_name
when "hello_world", "layout_test", "rendering_without_layout",
"rendering_nothing_on_layout", "render_text_hello_world",
"render_text_hello_world_with_layout",
"hello_world_with_layout_false",
"partial_only", "partial_only_with_layout",
"accessing_params_in_template",
"accessing_params_in_template_with_layout",
"render_with_explicit_template",
"render_with_explicit_string_template",
"update_page", "update_page_with_instance_variables"
"layouts/standard"
when "action_talk_to_layout", "layout_overriding_layout"
"layouts/talk_from_action"
when "render_implicit_html_template_from_xhr_request"
(request.xhr? ? 'layouts/xhr' : 'layouts/standard')
end
end
end
tests TestController
def setup
# enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
# a more accurate simulation of what happens in "real life".
super
@controller.logger = Logger.new(nil)
@request.host = "www.nextangle.com"
end
def test_enum_rjs_test
ActiveSupport::SecureRandom.stubs(:base64).returns("asdf")
get :enum_rjs_test
body = %{
$$(".product").each(function(value, index) {
new Effect.Highlight(element,{});
new Effect.Highlight(value,{});
Sortable.create(value, {onUpdate:function(){new Ajax.Request('/render_other_test/test/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(value) + '&authenticity_token=' + encodeURIComponent('asdf')})}});
new Draggable(value, {});
});
}.gsub(/^ /, '').strip
assert_equal body, @response.body
end
def test_explicitly_rendering_an_html_template_with_implicit_html_template_renders_should_be_possible_from_an_rjs_template
[:js, "js"].each do |format|
assert_nothing_raised do
get :render_explicit_html_template, :format => format
assert_equal %(document.write("Hello world\\n");), @response.body
end
end
end
def test_render_custom_code_rjs
get :render_custom_code_rjs
assert_response 404
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
def test_render_in_an_rjs_template_should_pick_html_templates_when_available
[:js, "js"].each do |format|
assert_nothing_raised do
get :render_implicit_html_template, :format => format
assert_equal %(document.write("Hello world\\n");), @response.body
end
end
end
def test_render_rjs_template_explicitly
get :render_js_with_explicit_template
assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
end
def test_rendering_rjs_action_explicitly
get :render_js_with_explicit_action_template
assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
end
def test_render_rjs_with_default
get :delete_with_js
assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
end
def test_update_page
get :update_page
assert_template nil
assert_equal 'text/javascript; charset=utf-8', @response.headers['Content-Type']
assert_equal 2, @response.body.split($/).length
end
def test_update_page_with_instance_variables
get :update_page_with_instance_variables
assert_template nil
assert_equal 'text/javascript; charset=utf-8', @response.headers["Content-Type"]
assert_match(/balance/, @response.body)
assert_match(/\$37/, @response.body)
end
def test_update_page_with_view_method
get :update_page_with_view_method
assert_template nil
assert_equal 'text/javascript; charset=utf-8', @response.headers["Content-Type"]
assert_match(/2 people/, @response.body)
end
def test_should_render_html_formatted_partial_with_rjs
xhr :get, :partial_as_rjs
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
def test_should_render_html_formatted_partial_with_rjs_and_js_format
xhr :get, :respond_to_partial_as_rjs
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
def test_should_render_with_alternate_default_render
xhr :get, :render_alternate_default
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
def test_using_custom_render_option
get :render_simon_says
assert_equal "Simon says: foo", @response.body
......
......@@ -517,15 +517,6 @@ def partial
render :partial => 'partial'
end
def render_alternate_default
# For this test, the method "default_render" is overridden:
@alternate_default_render = lambda do
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
end
def render_to_string_with_partial
@partial_only = render_to_string :partial => "partial_only"
@partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") }
......
page.remove 'person'
page.visual_effect :highlight, "project-#{@project_id}"
page.select('.product').each do |value|
page.visual_effect :highlight
page.visual_effect :highlight, value
page.sortable(value, :url => { :action => "order" })
page.draggable(value)
end
\ No newline at end of file
page[:body].visual_effect :highlight
\ No newline at end of file
page.call "document.write", render(:partial => "one.html.erb")
......@@ -178,11 +178,6 @@ h5. +remote_function+
h5. +update_page+
h3. JavaScript the Rails way: RJS
In the last section we sent some AJAX requests to the server, and inserted the HTML response into the page (with the +:update+ option). However, sometimes a more complicated interaction with the page is needed, which you can either achieve with JavaScript... or with RJS! You are sending JavaScript instructions to the server in both cases, but while in the former case you have to write vanilla JavaScript, in the second you can code Rails, and sit back while Rails generates the JavaScript for you - so basically RJS is a Ruby DSL to write JavaScript in your Rails code.
h4. JavaScript without RJS
First we'll check out how to send JavaScript to the server manually. You are practically never going to need this, but it's interesting to understand what's going on under the hood.
......@@ -198,20 +193,6 @@ end
What happens here is that by specifying the Content-Type header variable, we instruct the browser to evaluate the text we are sending over (rather than displaying it as plain text, which is the default behavior).
h4. Inline RJS
As we said, the purpose of RJS is to write Ruby which is then auto-magically turned into JavaScript by Rails. The above example didn't look too Ruby-esque so let's see how to do it the Rails way:
<ruby>
def javascript_test
render :update do |page|
page.alert "Hello from inline RJS"
end
end
</ruby>
The above code snippet does exactly the same as the one in the previous section - going about it much more elegantly though. You don't need to worry about headers,write ugly JavaScript code into a string etc. When the first parameter to +render+ is +:update+, Rails expects a block with a single parameter (+page+ in our case, which is the traditional naming convention) which is an instance of the JavaScriptGenerator:"http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper/JavaScriptGenerator/GeneratorMethods.html" object. As it's name suggests, JavaScriptGenerator is responsible for generating JavaScript from your Ruby code. You can execute multiple method calls on the +page+ instance - it's all turned into JavaScript code and sent to the server with the appropriate Content Type, "text/javascript".
h4. RJS Templates
If you don't want to clutter your controllers with view code (especially when your inline RJS is more than a few lines), you can move your RJS code to a template file. RJS templates should go to the +/app/views/+ directory, just as +.html.erb+ or any other view files of the appropriate controller, conventionally named +js.rjs+.
......@@ -222,113 +203,6 @@ To rewrite the above example, you can leave the body of the action empty, and cr
page.alert "Hello from inline RJS"
</ruby>
h4. RJS Reference
In this section we'll go through the methods RJS offers.
h5. JavaScriptGenerator Methods
h6. DOM Element Manipulation
It is possible to manipulate multiple elements at once through the +page+ JavaScriptGenerator instance. Let's see this in action:
<ruby>
page.show :div_one, :div_two
page.hide :div_one
page.remove :div_one, :div_two, :div_three
page.toggle :other_div
</ruby>
The above methods (+show+, +hide+, +remove+, +toggle+) have the same semantics as the Prototype methods of the same name. You can pass an arbitrary number (but at least one) of DOM ids to these calls.
h6. Inserting and Replacing Content
You can insert content into an element on the page with the +insert_html+ method:
<ruby>
page.insert_html :top, :result, '42'
</ruby>
The first parameter is the position of the new content relative to the element specified by the second parameter, a DOM id.
Position can be one of these four values:
*** +:before+ Inserts the response text just before the target element.
*** +:after+ The response is inserted after the target element.
*** +:top+ Inserts the text into the target element, before it's original content.
*** +:bottom+ The counterpart of +:top+: the response is inserted after the target element's original content.
The third parameter can either be a string, or a hash of options to be passed to ActionView::Base#render - for example:
<ruby>
page.insert_html :top, :result, :partial => "the_answer"
</ruby>
You can replace the contents (innerHTML) of an element with the +replace_html+ method. The only difference is that since it's clear where should the new content go, there is no need for a position parameter - so +replace_html+ takes only two arguments,
the DOM id of the element you wish to modify and a string or a hash of options to be passed to ActionView::Base#render.
h6. Delay
You can delay the execution of a block of code with +delay+:
<ruby>
page.delay(10) { page.alert('Hey! Just waited 10 seconds') }
</ruby>
+delay+ takes one parameter (time to wait in seconds) and a block which will be executed after the specified time has passed - whatever else follows a +page.delay+ line is executed immediately, the delay affects only the code in the block.
h6. Reloading and Redirecting
You can reload the page with the +reload+ method:
<ruby>
page.reload
</ruby>
When using AJAX, you can't rely on the standard +redirect_to+ controller method - you have to use the +page+'s instance method, also called +redirect_to+:
<ruby>
page.redirect_to some_url
</ruby>
h6. Generating Arbitrary JavaScript
Sometimes even the full power of RJS is not enough to accomplish everything, but you still don't want to drop to pure JavaScript. A nice golden mean is offered by the combination of +<<+, +assign+ and +call+ methods:
<ruby>
page << "alert('1+1 equals 3')"
</ruby>
So +<<+ is used to execute an arbitrary JavaScript statement, passed as string to the method. The above code is equivalent to:
<ruby>
page.assign :result, 3
page.call :alert, '1+1 equals ' + result
</ruby>
+assign+ simply assigns a value to a variable. +call+ is similar to +<<+ with a slightly different syntax: the first parameter is the name of the function to call, followed by the list of parameters passed to the function.
h6. Class Proxies
h5. Element Proxies
h5. Collection Proxies
h5. RJS Helpers
h3. I Want my Yellow Thingy: Quick overview of Script.aculo.us
h4. Introduction
h4. Visual Effects
h4. Drag and Drop
h3. Testing JavaScript
JavaScript testing reminds me the definition of the world 'classic' by Mark Twain: "A classic is something that everybody wants to have read and nobody wants to read." It's similar with JavaScript testing: everyone would like to have it, yet it's not done by too much developers as it is tedious, complicated, there is a proliferation of tools and no consensus/accepted best practices, but we will nevertheless take a stab at it:
......
......@@ -250,18 +250,6 @@ render :inline =>
"xml.p {'Horrid coding practice!'}", :type => :builder
</ruby>
h5. Using +render+ with +:update+
You can also render JavaScript-based page updates inline using the +:update+ option to +render+:
<ruby>
render :update do |page|
page.replace_html 'warning', "Invalid options supplied"
end
</ruby>
WARNING: Placing JavaScript updates in your controller may seem to streamline small updates, but it defeats the MVC orientation of Rails and will make it harder for other developers to follow the logic of your project. We recommend using a separate RJS template instead, no matter how small the update.
h5. Rendering Text
You can send plain text - with no markup at all - back to the browser by using the +:text+ option to +render+:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册