Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added button_to as a form-based solution to deal with harmful actions…

… that should be hidden behind POSTs. This makes it just as easy as link_to to create a safe trigger for actions like destroy, although it's limited by being a block element, the fixed look, and a no-no inside other forms. #1371 [tom@moertel.com]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1437 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit 43c470fae468ef63e0d5c3dc1e202925685fd47b 1 parent 70757cb
@dhh dhh authored
View
2  actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* Added button_to as a form-based solution to deal with harmful actions that should be hidden behind POSTs. This makes it just as easy as link_to to create a safe trigger for actions like destroy, although it's limited by being a block element, the fixed look, and a no-no inside other forms. #1371 [tom@moertel.com]
+
* Fixed image_tag so an exception is not thrown just because the image is missing and alt value can't be generated #1395 [Marcel]
* Added a third parameter to TextHelper#auto_link called href_options for specifying additional tag options on the links generated #1401 [tyler.kovacs@gmail.com]. Example: auto_link(text, :all, { :target => "_blank" }) to have all the generated links open in a new window.
View
93 actionpack/lib/action_view/helpers/url_helper.rb
@@ -33,6 +33,67 @@ def link_to(name, options = {}, html_options = nil, *parameters_for_method_refer
end
end
+ # Generates a form containing a sole button that submits to the
+ # URL given by _options_. Use this method instead of +link_to+
+ # for actions that do not have the safe HTTP GET semantics
+ # implied by using a hypertext link.
+ #
+ # The parameters are the same as for +link_to+. Any _html_options_
+ # that you pass will be applied to the inner +input+ element.
+ # In particular, pass
+ #
+ # :disabled => true/false
+ #
+ # as part of _html_options_ to control whether the button is
+ # disabled. The generated form element is given the class
+ # 'button-to', to which you can attach CSS styles for display
+ # purposes.
+ #
+ # Example 1:
+ #
+ # # inside of controller for "feeds"
+ # button_to "Edit", :action => 'edit', :id => 3
+ #
+ # Generates the following HTML (sans formatting):
+ #
+ # <form method="post" action="/feeds/edit/3" class="button-to">
+ # <div><input value="Edit" type="submit" /></div>
+ # </form>
+ #
+ # Example 2:
+ #
+ # button_to "Destroy", { :action => 'destroy', :id => 3 },
+ # :confirm => "Are you sure?"
+ #
+ # Generates the following HTML (sans formatting):
+ #
+ # <form method="post" action="/feeds/destroy/3" class="button-to">
+ # <div><input onclick="return confirm('Are you sure?');"
+ # value="Destroy" type="submit" />
+ # </div>
+ # </form>
+ #
+ # *NOTE*: This method generates HTML code that represents a form.
+ # Forms are "block" content, which means that you should not try to
+ # insert them into your HTML where only inline content is expected.
+ # For example, you can legally insert a form inside of a +div+ or
+ # +td+ element or in between +p+ elements, but not in the middle of
+ # a run of text, nor can you place a form within another form.
+ # (Bottom line: Always validate your HTML before going public.)
+
+ def button_to(name, options = {}, html_options = nil)
+ html_options = (html_options || {}).stringify_keys
+ convert_boolean_attributes!(html_options, %w( disabled ))
+ convert_confirm_option_to_javascript!(html_options)
+ url, name = options.is_a?(String) ?
+ [ options, name || options ] :
+ [ url_for(options), name || url_for(options) ]
+ html_options.merge!("type" => "submit", "value" => name)
+ "<form method=\"post\" action=\"#{h url}\" class=\"button-to\"><div>" +
+ tag("input", html_options) + "</div></form>"
+ end
+
+
# This tag is deprecated. Combine the link_to and AssetTagHelper::image_tag yourself instead, like:
# link_to(image_tag("rss", :size => "30x45", :border => 0), "http://www.example.com")
def link_image_to(src, options = {}, html_options = {}, *parameters_for_method_reference)
@@ -157,6 +218,36 @@ def convert_confirm_option_to_javascript!(html_options)
html_options["onclick"] = "return confirm('#{confirm.gsub(/'/, '\\\\\'')}');"
end
end
+
+ # Processes the _html_options_ hash, converting the boolean
+ # attributes from true/false form into the form required by
+ # HTML/XHTML. (An attribute is considered to be boolean if
+ # its name is listed in the given _bool_attrs_ array.)
+ #
+ # More specifically, for each boolean attribute in _html_options_
+ # given as:
+ #
+ # "attr" => bool_value
+ #
+ # if the the associated _bool_value_ evaluates to true, it is
+ # replaced with the attribute's name; otherwise the attribute is
+ # removed from the _html_options_ hash. (See the XHTML 1.0 spec,
+ # section 4.5 "Attribute Minimization" for more:
+ # http://www.w3.org/TR/xhtml1/#h-4.5)
+ #
+ # Returns the updated _html_options_ hash, which is also modified
+ # in place.
+ #
+ # Example:
+ #
+ # convert_boolean_attributes!( html_options,
+ # %w( checked disabled readonly ) )
+
+ def convert_boolean_attributes!(html_options, bool_attrs)
+ bool_attrs.each { |x| html_options[x] = x if html_options.delete(x) }
+ html_options
+ end
+
end
end
-end
+end
View
22 actionpack/test/template/url_helper_test.rb
@@ -21,6 +21,28 @@ def url_for(options, *parameters_for_method_reference)
end
# todo: missing test cases
+ def test_button_to_with_straight_url
+ assert_equal "<form method=\"post\" action=\"http://www.example.com\" class=\"button-to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com")
+ end
+
+ def test_button_to_with_javascript_confirm
+ assert_equal(
+ "<form method=\"post\" action=\"http://www.example.com\" class=\"button-to\"><div><input onclick=\"return confirm('Are you sure?');\" type=\"submit\" value=\"Hello\" /></div></form>",
+ button_to("Hello", "http://www.example.com", :confirm => "Are you sure?")
+ )
+ end
+
+ def test_button_to_enabled_disabled
+ assert_equal(
+ "<form method=\"post\" action=\"http://www.example.com\" class=\"button-to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>",
+ button_to("Hello", "http://www.example.com", :disabled => false)
+ )
+ assert_equal(
+ "<form method=\"post\" action=\"http://www.example.com\" class=\"button-to\"><div><input disabled=\"disabled\" type=\"submit\" value=\"Hello\" /></div></form>",
+ button_to("Hello", "http://www.example.com", :disabled => true)
+ )
+ end
+
def test_link_tag_with_straight_url
assert_equal "<a href=\"http://www.example.com\">Hello</a>", link_to("Hello", "http://www.example.com")
end
Please sign in to comment.
Something went wrong with that request. Please try again.