diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index 38711c8462a9028dcf1be9d405730eaa81a70fbe..dfda6618e75fe6f1e68f9afc6cf8cf3ccee94dc2 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -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 diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb index c72370e49d4771ed7721f4f1d0a52ccd94582d85..878484eb57853683cd6be5a2b416d825ab091f33 100644 --- a/actionpack/test/controller/assert_select_test.rb +++ b/actionpack/test/controller/assert_select_test.rb @@ -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", "
foo
\n
foo
" - 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", "
foo
" - page.replace_html "test2", "
foo
" - 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{} 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", "
foo
\n
foo
" - 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", "
foo
" - page.replace_html "test2", "
foo
" - 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 @@ -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 diff --git a/actionpack/test/controller/new_base/render_rjs_test.rb b/actionpack/test/controller/new_base/render_rjs_test.rb deleted file mode 100644 index 74bf865b545b15d2cd946517473e46764fb786ea..0000000000000000000000000000000000000000 --- a/actionpack/test/controller/new_base/render_rjs_test.rb +++ /dev/null @@ -1,71 +0,0 @@ -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 diff --git a/actionpack/test/controller/render_js_test.rb b/actionpack/test/controller/render_js_test.rb index 491c98a0fdd57821309c2c4b3775208db000bf6b..f070109b2780cf08dba05b82705e6ee26d319599 100644 --- a/actionpack/test/controller/render_js_test.rb +++ b/actionpack/test/controller/render_js_test.rb @@ -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 diff --git a/actionpack/test/controller/render_other_test.rb b/actionpack/test/controller/render_other_test.rb index eda777e7a7b4410fce0b33521294aa4a37a55b02..b5e74e373d48507d8db411f550064581c5d3655f 100644 --- a/actionpack/test/controller/render_other_test.rb +++ b/actionpack/test/controller/render_other_test.rb @@ -1,6 +1,4 @@ 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 diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index be492152f20281ba3a41af2e34c43653402e247f..e62f3155c5271c1bb3e2405fbd996d7d725e5c03 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -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") } diff --git a/actionpack/test/fixtures/test/delete_with_js.rjs b/actionpack/test/fixtures/test/delete_with_js.rjs deleted file mode 100644 index 4b75a955ad4e1e65a98ac6663ca0583ca4973e3d..0000000000000000000000000000000000000000 --- a/actionpack/test/fixtures/test/delete_with_js.rjs +++ /dev/null @@ -1,2 +0,0 @@ -page.remove 'person' -page.visual_effect :highlight, "project-#{@project_id}" diff --git a/actionpack/test/fixtures/test/enum_rjs_test.rjs b/actionpack/test/fixtures/test/enum_rjs_test.rjs deleted file mode 100644 index e3004076a8ffd1d45b4cfad18efde0d3bc468e84..0000000000000000000000000000000000000000 --- a/actionpack/test/fixtures/test/enum_rjs_test.rjs +++ /dev/null @@ -1,6 +0,0 @@ -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 diff --git a/actionpack/test/fixtures/test/greeting.js.rjs b/actionpack/test/fixtures/test/greeting.js.rjs deleted file mode 100644 index 469fcd8e15ba81b98a5276da9e0e6dacc5993a63..0000000000000000000000000000000000000000 --- a/actionpack/test/fixtures/test/greeting.js.rjs +++ /dev/null @@ -1 +0,0 @@ -page[:body].visual_effect :highlight \ No newline at end of file diff --git a/actionpack/test/fixtures/test/render_explicit_html_template.js.rjs b/actionpack/test/fixtures/test/render_explicit_html_template.js.rjs deleted file mode 100644 index 4eb12fd6af717765807983496a16247522b8b772..0000000000000000000000000000000000000000 --- a/actionpack/test/fixtures/test/render_explicit_html_template.js.rjs +++ /dev/null @@ -1 +0,0 @@ -page.call "document.write", render(:partial => "one.html.erb") diff --git a/actionpack/test/fixtures/test/render_implicit_html_template.js.rjs b/actionpack/test/fixtures/test/render_implicit_html_template.js.rjs deleted file mode 100644 index 3d68041756402fbf127c26a6eb5246d18e054a65..0000000000000000000000000000000000000000 --- a/actionpack/test/fixtures/test/render_implicit_html_template.js.rjs +++ /dev/null @@ -1 +0,0 @@ -page.call "document.write", render(:partial => "one") diff --git a/railties/guides/source/ajax_on_rails.textile b/railties/guides/source/ajax_on_rails.textile index b80df4aa58902fdc3b9fe9f74f985a9ab53ed52f..708a6f65a44c0f6579e55fbe2ade74deaa03fab9 100644 --- a/railties/guides/source/ajax_on_rails.textile +++ b/railties/guides/source/ajax_on_rails.textile @@ -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: - - -def javascript_test - render :update do |page| - page.alert "Hello from inline RJS" - end -end - - -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" -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: - - -page.show :div_one, :div_two -page.hide :div_one -page.remove :div_one, :div_two, :div_three -page.toggle :other_div - - -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: - - -page.insert_html :top, :result, '42' - - -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: - - -page.insert_html :top, :result, :partial => "the_answer" - - -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+: - - -page.delay(10) { page.alert('Hey! Just waited 10 seconds') } - - -+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: - - -page.reload - - -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+: - - -page.redirect_to some_url - - -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: - - - page << "alert('1+1 equals 3')" - - -So +<<+ is used to execute an arbitrary JavaScript statement, passed as string to the method. The above code is equivalent to: - - - page.assign :result, 3 - page.call :alert, '1+1 equals ' + result - - -+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: diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile index 8ea63f2ce3ea3e2dfd156ec38d8c806ddd3a95c7..da316a2db391a9cc6fb6ace6c43f5bd393cbd1ee 100644 --- a/railties/guides/source/layouts_and_rendering.textile +++ b/railties/guides/source/layouts_and_rendering.textile @@ -250,18 +250,6 @@ render :inline => "xml.p {'Horrid coding practice!'}", :type => :builder -h5. Using +render+ with +:update+ - -You can also render JavaScript-based page updates inline using the +:update+ option to +render+: - - -render :update do |page| - page.replace_html 'warning', "Invalid options supplied" -end - - -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+: