From 3822a322a82a19a9341a21a0cb1e36653da09c46 Mon Sep 17 00:00:00 2001 From: Justin Schiff Date: Wed, 5 Aug 2015 09:38:43 -0700 Subject: Make disable_with default in submit_tag Prevents double submission by making disable_with the default. Default disable_with option will only be applied if user has not specified her/his own disable_with option, whether that is in the `data-disable-with` string form or the `:data => { :disable_with => "Saving..." }` hash form. disable_with will default to the value attribute. A configuration option was added to opt out of this functionality if the user so desires. `config.action_view.automatically_disable_submit_tag = false` --- actionview/CHANGELOG.md | 5 +++ actionview/lib/action_view/base.rb | 4 +++ .../lib/action_view/helpers/form_tag_helper.rb | 32 ++++++++++++----- actionview/test/template/form_helper_test.rb | 18 +++++----- actionview/test/template/form_tag_helper_test.rb | 40 +++++++++++++++++++++- guides/source/configuring.md | 3 ++ 6 files changed, 83 insertions(+), 19 deletions(-) diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index edc78118fb..90c9c2171c 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1,3 +1,8 @@ +* Make `disable_with` the default behavior for submit tags. Disables the + button on submit to prevent double submits. + + *Justin Schiff* + * Add a break_sequence option to word_wrap so you can specify a custom break. * Mauricio Gomez * diff --git a/actionview/lib/action_view/base.rb b/actionview/lib/action_view/base.rb index 43124bb904..72ca6f7ec6 100644 --- a/actionview/lib/action_view/base.rb +++ b/actionview/lib/action_view/base.rb @@ -161,6 +161,10 @@ module ActionView #:nodoc: cattr_accessor :raise_on_missing_translations @@raise_on_missing_translations = false + # Specify whether submit_tag should automatically disable on click + cattr_accessor :automatically_disable_submit_tag + @@automatically_disable_submit_tag = true + class_attribute :_routes class_attribute :logger diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb index d36701955a..af684e05c6 100644 --- a/actionview/lib/action_view/helpers/form_tag_helper.rb +++ b/actionview/lib/action_view/helpers/form_tag_helper.rb @@ -414,34 +414,48 @@ module ActionView # the form is processed normally, otherwise no action is taken. # * :disable_with - Value of this parameter will be used as the value for a # disabled version of the submit button when the form is submitted. This feature is - # provided by the unobtrusive JavaScript driver. + # provided by the unobtrusive JavaScript driver. To disable this feature for a single submit tag + # pass :data => { disable_with: false } Defaults to value attribute. # # ==== Examples # submit_tag - # # => + # # => # # submit_tag "Edit this article" - # # => + # # => # # submit_tag "Save edits", disabled: true - # # => + # # => # - # submit_tag "Complete sale", data: { disable_with: "Please wait..." } - # # => + # submit_tag "Complete sale", data: { disable_with: "Submitting..." } + # # => # # submit_tag nil, class: "form_submit" # # => # # submit_tag "Edit", class: "edit_button" - # # => + # # => # # submit_tag "Save", data: { confirm: "Are you sure?" } - # # => + # # => # def submit_tag(value = "Save changes", options = {}) options = options.stringify_keys + tag_options = { "type" => "submit", "name" => "commit", "value" => value }.update(options) + + if ActionView::Base.automatically_disable_submit_tag + unless tag_options["data-disable-with"] == false || (tag_options["data"] && tag_options["data"][:disable_with] == false) + disable_with_text = tag_options["data-disable-with"] + disable_with_text ||= tag_options["data"][:disable_with] if tag_options["data"] + disable_with_text ||= value.clone + tag_options.deep_merge!("data" => { "disable_with" => disable_with_text }) + else + tag_options.delete("data-disable-with") + tag_options["data"].delete(:disable_with) if tag_options["data"] + end + end - tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options) + tag :input, tag_options end # Creates a button element that defines a submit button, diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb index b8cb5bd746..37f2d7cad6 100644 --- a/actionview/test/template/form_helper_test.rb +++ b/actionview/test/template/form_helper_test.rb @@ -1577,7 +1577,7 @@ class FormHelperTest < ActionView::TestCase "" + "" + "" + - "" + + "" + "" + "" end @@ -1854,7 +1854,7 @@ class FormHelperTest < ActionView::TestCase expected = whole_form("/posts/44", "edit_post_44", "edit_post", method: "patch") do "" + - "" + "" end assert_dom_equal expected, output_buffer @@ -1875,7 +1875,7 @@ class FormHelperTest < ActionView::TestCase "" + "" + "" + - "" + "" end assert_dom_equal expected, output_buffer @@ -2083,7 +2083,7 @@ class FormHelperTest < ActionView::TestCase expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do "
" + "
" + - "" + "" end assert_dom_equal expected, output_buffer @@ -2101,7 +2101,7 @@ class FormHelperTest < ActionView::TestCase expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do "
" + "
" + - "" + "" end assert_dom_equal expected, output_buffer @@ -2226,7 +2226,7 @@ class FormHelperTest < ActionView::TestCase end expected = whole_form('/posts', 'new_post', 'new_post') do - "" + "" end assert_dom_equal expected, output_buffer @@ -2240,7 +2240,7 @@ class FormHelperTest < ActionView::TestCase end expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do - "" + "" end assert_dom_equal expected, output_buffer @@ -2254,7 +2254,7 @@ class FormHelperTest < ActionView::TestCase end expected = whole_form do - "" + "" end assert_dom_equal expected, output_buffer @@ -2268,7 +2268,7 @@ class FormHelperTest < ActionView::TestCase end expected = whole_form('/posts/123', 'edit_another_post', 'edit_another_post', method: 'patch') do - "" + "" end assert_dom_equal expected, output_buffer diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb index f602c82c42..a9d9562580 100644 --- a/actionview/test/template/form_tag_helper_test.rb +++ b/actionview/test/template/form_tag_helper_test.rb @@ -433,6 +433,44 @@ class FormTagHelperTest < ActionView::TestCase ) end + def test_empty_submit_tag + assert_dom_equal( + %(), + submit_tag("Save") + ) + end + + def test_empty_submit_tag_with_opt_out + ActionView::Base.automatically_disable_submit_tag = false + assert_dom_equal( + %(), + submit_tag("Save") + ) + ensure + ActionView::Base.automatically_disable_submit_tag = true + end + + def test_data_disable_with_string + assert_dom_equal( + %(), + submit_tag("Save", { "data-disable-with" => "Processing...", "data-confirm" => "Are you sure?" }) + ) + end + + def test_data_disable_with_boolean + assert_dom_equal( + %(), + submit_tag("Save", { "data-disable-with" => false, "data-confirm" => "Are you sure?" }) + ) + end + + def test_data_hash_disable_with_boolean + assert_dom_equal( + %(), + submit_tag("Save", { :data => { :confirm => "Are you sure?", :disable_with => false } }) + ) + end + def test_submit_tag_with_no_onclick_options assert_dom_equal( %(), @@ -442,7 +480,7 @@ class FormTagHelperTest < ActionView::TestCase def test_submit_tag_with_confirmation assert_dom_equal( - %(), + %(), submit_tag("Save", :data => { :confirm => "Are you sure?" }) ) end diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 47c275609e..df9704830e 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -451,6 +451,9 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. * `config.action_view.raise_on_missing_translations` determines whether an error should be raised for missing translations. +* `config.action_view.automatically_disable_submit_tag` determines whether + submit_tag should automatically disable on click, this defaults to true. + ### Configuring Action Mailer There are a number of settings available on `config.action_mailer`: -- cgit v1.2.3