I am delighted to report that the button_to helper has been added to the Ruby on Rails web-development framework. David applied the patch earlier today, and so button_to will be in the much-anticipated Rails 1.0 release.
David’s change-log entry summarizes the patch well:
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.
David does a good job of highlighting the helper’s limitations. I’ll take this opportunity to elaborate on each.
It is a block element
The button_to helper creates a small form, which in HTML is considered block content, just like the p, div, and blockquote elements are. Basically, block content cannot be mixed into runs of text. But links can: links are inline content. Thus button_to cannot be used as a drop-in replacement for every occurrence of link_to that might be unsafe; it works only for those occurrences within block-accepting contexts.
Luckily for us, when designers use links to trigger unsafe actions, they rarely slip such links into the middle of ordinary looking text. Naughty uses of link_to almost always occur within contexts that accept block content. In Rails-generated scaffolding code, for instance, the unsafe uses of link_to occur within table cells, and table cells have a flow content model, which accepts both inline and block content. So button_to works great for the default cases in Rails.
It has a fixed look
As its name implies, button_to creates buttons. Buttons don’t look like links and aren’t styled the same way that links are. For some design scenarios, this might be a problem.
(My view is that links should not be used to trigger unsafe actions. In the same way that action-triggering GET requests violate the spirit of the HTTP standards, action-triggering hypertext links violate the spirit of the HTML standards. For this reason, I view this limitation as a feature.)
It is a no-no inside other forms
Forms cannot be nested, and so button_to cannot be used inside of forms.
Fortunately, this limitation usually doesn’t matter because when we are inside of a form, we can use its buttons instead of button_to-created buttons to trigger actions. Still, there are some circumstances where it does matter, such as the “Amazon.com wish list” scenario. In this scenario, we should consider other options.
The bottom line: Pick the low-hanging fruit
While button_to has its limitations, it does provide a simple solution to the unsafe-GET problem for most real-world cases. I am glad that it is now a part of Rails, and I offer a big thank-you to David for accepting the patch.