Skip to content

Commit

Permalink
Allow overriding button_to_generates_button_tag per-invocation
Browse files Browse the repository at this point in the history
ref: rails#40747

The global config is great for new projects, but for large existing projects, auditing every `button_to` call could be overwhelming enough to not bother.

This PR allows you to set if a button should always be returned per-invocation. This way you can gradually opt in to the config, or you can use it only in parts of your codebase.

```ruby

button_to("Save", "http://www.example.com") # renders <input>
button_to("Save", "http://www.example.com", button_tag: true) # renders <button>
button_to("Save", "http://www.example.com", button_tag: false) # renders <input>

button_to("Save", "http://www.example.com") # renders <button>
button_to("Save", "http://www.example.com", button_tag: true) # renders <button>
button_to("Save", "http://www.example.com", button_tag: false) # renders <input>
```
  • Loading branch information
ghiculescu committed Sep 5, 2023
1 parent 31052d0 commit 1830cc8
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 1 deletion.
18 changes: 18 additions & 0 deletions actionview/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
* `button_to` now accepts a `button_tag:` option, to override the `button_to_generates_button_tag` config

```ruby
# With config.action_view.button_to_generates_button_tag = false

button_to("Save", "http://www.example.com", button_tag: true) # renders <button>
button_to("Save", "http://www.example.com", button_tag: false) # renders <input>
button_to("Save", "http://www.example.com") # renders <input>

# With config.action_view.button_to_generates_button_tag = true

button_to("Save", "http://www.example.com", button_tag: true) # renders <button>
button_to("Save", "http://www.example.com", button_tag: false) # renders <input>
button_to("Save", "http://www.example.com") # renders <button>
```

*Alex Ghiculescu*

* Don't double-encode nested `field_id` and `field_name` index values
Pass `index: @options` as a default keyword argument to `field_id` and
Expand Down
10 changes: 9 additions & 1 deletion actionview/lib/action_view/helpers/url_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,13 @@ def link_to(name = nil, options = nil, html_options = nil, &block)
# # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
# # </form>"
#
# By default, `config.action_view.button_to_generates_button_tag` is `true`, and a `<button>`
# is always returned. If `config.action_view.button_to_generates_button_tag` is `false`, an `<input>`
# will be returned if a block is not given. To set this per-invocation, pass the `button` option:
#
# <%= button_to "New", new_article_path, button: true %> # Renders a button
# <%= button_to "New", new_article_path, button: false %> # Renders an input
#
# Most values in +html_options+ are passed through to the button element,
# but there are a few special options:
#
Expand Down Expand Up @@ -387,12 +394,13 @@ def button_to(name = nil, options = nil, html_options = nil, &block)
""
end

use_button = html_options.key?("button_tag") ? html_options.delete("button_tag") : button_to_generates_button_tag
html_options = convert_options_to_data_attributes(options, html_options)
html_options["type"] = "submit"

button = if block_given?
content_tag("button", html_options, &block)
elsif button_to_generates_button_tag
elsif use_button
content_tag("button", name || url, html_options, &block)
else
html_options["value"] = name || url
Expand Down
12 changes: 12 additions & 0 deletions actionview/test/template/url_helper_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,18 @@ def test_button_to_generates_input_when_button_to_generates_button_tag_false
ActionView::Helpers::UrlHelper.button_to_generates_button_tag = old_value
end

def test_button_to_generates_button_when_button_to_generates_button_tag_false_but_argument_is_provided
old_value = ActionView::Helpers::UrlHelper.button_to_generates_button_tag
ActionView::Helpers::UrlHelper.button_to_generates_button_tag = false

assert_dom_equal(
%{<form method="post" action="http://www.example.com" class="button_to"><button type="submit">Save</button></form>},
button_to("Save", "http://www.example.com", button_tag: true)
)
ensure
ActionView::Helpers::UrlHelper.button_to_generates_button_tag = old_value
end

def test_button_to_with_content_exfiltration_prevention
with_prepend_content_exfiltration_prevention(true) do
assert_dom_equal(
Expand Down

0 comments on commit 1830cc8

Please sign in to comment.