From 0b1d6fd9c87fd4a8459b0f560db626bf36a19618 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 28 May 2006 00:33:53 +0000 Subject: [PATCH] Added :method option to UrlHelper#link_to, which allows for using other verbs than GET for the link. This replaces the :post option, which is now deprecated. Example: link_to "Destroy", person_url(:id => person), :method => :delete [DHH] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4370 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- actionpack/CHANGELOG | 2 + .../lib/action_view/helpers/url_helper.rb | 40 +++++++++++++------ actionpack/test/template/url_helper_test.rb | 11 ++++- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 0b535e09994d8..0aad8365035bb 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Added :method option to UrlHelper#link_to, which allows for using other verbs than GET for the link. This replaces the :post option, which is now deprecated. Example: link_to "Destroy", person_url(:id => person), :method => :delete [DHH] + * follow_redirect doesn't complain about being redirected to the same controller. #5153 [dymo@mk.ukrtelecom.ua] * Add layout attribute to response object with the name of the layout that was rendered, or nil if none rendered. [Kevin Clark kevin.clark@gmail.com] diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 5cbf72896127c..df728fd655ff9 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -38,16 +38,17 @@ def url_for(options = {}, *parameters_for_method_reference) # Another for creating a popup window, which is done by either passing :popup with true or the options of the window in # Javascript form. # - # And a third for making the link do a POST request (instead of the regular GET) through a dynamically added form element that - # is instantly submitted. Note that if the user has turned off Javascript, the request will fall back on the GET. So its - # your responsibility to determine what the action should be once it arrives at the controller. The POST form is turned on by - # passing :post as true. Note, it's not possible to use POST requests and popup targets at the same time (an exception will be thrown). + # And a third for making the link do a non-GET request through a dynamically added form element that is instantly submitted. + # Note that if the user has turned off Javascript, the request will fall back on the GET. So its + # your responsibility to determine what the action should be once it arrives at the controller. The form is turned on by + # passing :method with the option of either :post, :delete, or :put as the value. Usually only :post or :delete will make sense, though. + # Note, it's not possible to use method request and popup targets at the same time (an exception will be thrown). # # Examples: # link_to "Delete this page", { :action => "destroy", :id => @page.id }, :confirm => "Are you sure?" # link_to "Help", { :action => "help" }, :popup => true # link_to "Busy loop", { :action => "busy" }, :popup => ['new_window', 'height=300,width=600'] - # link_to "Destroy account", { :action => "destroy" }, :confirm => "Are you sure?", :post => true + # link_to "Destroy account", { :action => "destroy" }, :confirm => "Are you sure?", :method => :delete def link_to(name, options = {}, html_options = nil, *parameters_for_method_reference) if html_options html_options = html_options.stringify_keys @@ -249,19 +250,23 @@ def current_page?(options) private def convert_options_to_javascript!(html_options) - confirm, popup, post = html_options.delete("confirm"), html_options.delete("popup"), html_options.delete("post") + confirm, popup = html_options.delete("confirm"), html_options.delete("popup") + + # post is deprecated, but if its specified and method is not, assume that method = :post + method, post = html_options.delete("method"), html_options.delete("post") + method = :post if !method && post html_options["onclick"] = case - when popup && post + when popup && method raise ActionView::ActionViewError, "You can't use :popup and :post in the same link" when confirm && popup "if (#{confirm_javascript_function(confirm)}) { #{popup_javascript_function(popup)} };return false;" - when confirm && post - "if (#{confirm_javascript_function(confirm)}) { #{post_javascript_function} };return false;" + when confirm && method + "if (#{confirm_javascript_function(confirm)}) { #{method_javascript_function(method)} };return false;" when confirm "return #{confirm_javascript_function(confirm)};" - when post - "#{post_javascript_function}return false;" + when method + "#{method_javascript_function(method)}return false;" when popup popup_javascript_function(popup) + 'return false;' else @@ -277,8 +282,17 @@ def popup_javascript_function(popup) popup.is_a?(Array) ? "window.open(this.href,'#{popup.first}','#{popup.last}');" : "window.open(this.href);" end - def post_javascript_function - "var f = document.createElement('form'); this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href; f.submit();" + def method_javascript_function(method) + submit_function = + "var f = document.createElement('form'); f.style.display = 'none'; " + + "this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;" + + unless method == :post + submit_function << "var m = document.createElement('input'); m.setAttribute('type', 'hidden'); " + submit_function << "m.setAttribute('name', '_method'); m.setAttribute('value', '#{method}'); f.appendChild(m);" + end + + submit_function << "f.submit();" end # Processes the _html_options_ hash, converting the boolean diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 231e34751eecb..4d57bc65bee55 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -127,14 +127,21 @@ def test_link_tag_with_popup_and_javascript_confirm def test_link_tag_using_post_javascript assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :post => true) ) end + + def test_link_tag_using_delete_javascript + assert_dom_equal( + "Destroy", + link_to("Destroy", "http://www.example.com", :method => :delete) + ) + end def test_link_tag_using_post_javascript_and_confirm assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :post => true, :confirm => "Are you serious?") ) end