Skip to content

Commit 7d2be2e

Browse files
committed
Make button_to more model-aware
Infer HTTP verb `[method]` from a model or Array with model as the first argument to `button_to` when combined with a block: ```ruby button_to(Workshop.find(1)){ "Update" } #=> <form method="post" action="/workshops/1" class="button_to"> #=> <input type="hidden" name="_method" value="patch" autocomplete="off" /> #=> <button type="submit">Update</button> #=> </form> button_to([ Workshop.find(1), Session.find(1) ]) { "Update" } #=> <form method="post" action="/workshops/1/sessions/1" class="button_to"> #=> <input type="hidden" name="_method" value="patch" autocomplete="off" /> #=> <button type="submit">Update</button> #=> </form> ``` Prior to this change, the constructed `<form>` was always submitted with a `[method="post"]` and _always_ omitted the `<input type="hidden" name="_method" value="...">` field, regardless of the return value of the "model" argument's `#persisted?` predicate.
1 parent 9f98066 commit 7d2be2e

File tree

3 files changed

+91
-2
lines changed

3 files changed

+91
-2
lines changed

actionview/CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
* Infer HTTP verb `[method]` from a model or Array with model as the first
2+
argument to `button_to` when combined with a block:
3+
4+
```ruby
5+
button_to(Workshop.find(1)){ "Update" }
6+
#=> <form method="post" action="/workshops/1" class="button_to">
7+
#=> <input type="hidden" name="_method" value="patch" autocomplete="off" />
8+
#=> <button type="submit">Update</button>
9+
#=> </form>
10+
11+
button_to([ Workshop.find(1), Session.find(1) ]) { "Update" }
12+
#=> <form method="post" action="/workshops/1/sessions/1" class="button_to">
13+
#=> <input type="hidden" name="_method" value="patch" autocomplete="off" />
14+
#=> <button type="submit">Update</button>
15+
#=> </form>
16+
```
17+
18+
*Sean Doyle*
19+
120
* Add `:day_format` option to `date_select`
221

322
date_select("article", "written_on", day_format: ->(day) { day.ordinalize })

actionview/lib/action_view/helpers/url_helper.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,8 @@ def button_to(name = nil, options = nil, html_options = nil, &block)
332332
remote = html_options.delete("remote")
333333
params = html_options.delete("params")
334334

335-
method = html_options.delete("method").to_s
335+
method = (html_options.delete("method").presence || method_for_options(options)).to_s
336+
336337
method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : "".html_safe
337338

338339
form_method = method == "get" ? "get" : "post"
@@ -753,6 +754,16 @@ def add_method_to_attributes!(html_options, method)
753754
html_options["data-method"] = method
754755
end
755756

757+
def method_for_options(options)
758+
if options.is_a?(Array)
759+
method_for_options(options.last)
760+
elsif options.respond_to?(:persisted?)
761+
options.persisted? ? :patch : :post
762+
elsif options.respond_to?(:to_model)
763+
method_for_options(options.to_model)
764+
end
765+
end
766+
756767
STRINGIFIED_COMMON_METHODS = {
757768
get: "get",
758769
delete: "delete",

actionview/test/template/url_helper_test.rb

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ class UrlHelperTest < ActiveSupport::TestCase
3535
get "/other" => "foo#other"
3636
get "/article/:id" => "foo#article", :as => :article
3737
get "/category/:category" => "foo#category"
38-
resources :workshops
38+
resources :sessions
39+
resources :workshops do
40+
resources :sessions
41+
end
3942

4043
scope :engine do
4144
get "/" => "foo#bar"
@@ -161,6 +164,62 @@ def test_button_to_with_path
161164
)
162165
end
163166

167+
def test_button_to_with_new_record_model
168+
session = Session.new(nil)
169+
170+
assert_dom_equal(
171+
%{<form method="post" action="/sessions" class="button_to"><button type="submit">Create Session</button></form>},
172+
button_to("Create Session", session)
173+
)
174+
end
175+
176+
def test_button_to_with_new_record_model_and_block
177+
workshop = Workshop.new(nil)
178+
179+
assert_dom_equal(
180+
%{<form method="post" action="/workshops" class="button_to"><button type="submit">Create</button></form>},
181+
button_to(workshop) { "Create" }
182+
)
183+
end
184+
185+
def test_button_to_with_nested_new_record_model_and_block
186+
workshop = Workshop.new("1")
187+
session = Session.new(nil)
188+
189+
assert_dom_equal(
190+
%{<form method="post" action="/workshops/1/sessions" class="button_to"><button type="submit">Create</button></form>},
191+
button_to([workshop, session]) { "Create" }
192+
)
193+
end
194+
195+
def test_button_to_with_persisted_model
196+
workshop = Workshop.new("1")
197+
198+
assert_dom_equal(
199+
%{<form method="post" action="/workshops/1" class="button_to"><input type="hidden" name="_method" value="patch" autocomplete="off" /><button type="submit">Update</button></form>},
200+
button_to(workshop) { "Update" }
201+
)
202+
end
203+
204+
def test_button_to_with_persisted_model_and_block
205+
workshop = Workshop.new("1")
206+
207+
assert_dom_equal(
208+
%{<form method="post" action="/workshops/1" class="button_to"><input type="hidden" name="_method" value="patch" autocomplete="off" /><button type="submit">Update</button></form>},
209+
button_to(workshop) { "Update" }
210+
)
211+
end
212+
213+
def test_button_to_with_nested_persisted_model_and_block
214+
workshop = Workshop.new("1")
215+
session = Session.new("1")
216+
217+
assert_dom_equal(
218+
%{<form method="post" action="/workshops/1/sessions/1" class="button_to"><input type="hidden" name="_method" value="patch" autocomplete="off" /><button type="submit">Update</button></form>},
219+
button_to([workshop, session]) { "Update" }
220+
)
221+
end
222+
164223
def test_button_to_with_straight_url_and_request_forgery
165224
self.request_forgery = true
166225

0 commit comments

Comments
 (0)