Multiple Form Buttons in Rails

Updated June 30, 2009

Some people don't realize that forms can have multiple submit buttons. True, the vast majority of forms only have a single button, often simply labeled "Submit". But that's not true of all forms, and it's certainly not true of many of the forms that I've created for my clients. For example, a typical scenario is a form that has a "Confirm" button and a "Cancel" button.

The First Iteration

The standard way to create a submit button in Ruby on Rails is:

      <%= submit_tag "Confirm" %>
      <%= submit_tag "Cancel" %>

The "submit_tag" helper creates an HTML button; the HTML that    was produced by the helper is shown below:

      <input name="commit" type="submit" value="Confirm" />
      <input name="commit" type="submit" value="Cancel" />

As you can see, both HTML buttons receive a default name of "commit". The label for each button is defined by the value attribute. Upon submission, the params hash will have an entry called "commit" with a value of either "Confirm" or "Cancel" depending on which button was clicked. In your controller, this can be tested:

      if params['commit'] == "Confirm"
         # Do something
      else
         # Do something else
      end

The Second Iteration

There's a better way to do this, though. Rather than creating buttons that have a default name of "commit", you can actually assign whatever name you want. The revised code for the helper tags is shown below:

      <%= submit_tag "Confirm", :name => "confirm" %>
      <%= submit_tag "Cancel", :name => "cancel" %>

Now, in your controller, you can test which button was clicked with the code below:

      if params['confirm']
         # Do something
      else
         # Do something else
      end

This way takes advantage of the fact that information is only submitted for the button that was clicked. So, if there's an entry in the params hash for "confirm" then that button was the one that was clicked. There's no need to check the specific value of the hash entry; the existence of the key is suffcient to indicate which button was clicked. Plus, it just seems logically cleaner for each button to have its own distinct name.

Using Image Tags

Most of the forms that I create for clients have image buttons. Rails has an "image_submit_tag" helper that makes it easy to create image buttons for forms.

      <%= image_submit_tag "button_confirm.gif", :name => "confirm" %>
      <%= image_submit_tag "button_cancel.gif", :name => "cancel" %>

But image buttons have an unexpected wrinkle, or at least, a wrinkle that was unexpected to me when I first encountered it years ago in another language (Classic ASP, if you're interested). The params hash is a convenient hash provided by Rails that organizes the data posted by the form. After submitting using the Confirm image button, the test for the existence of a "confirm" key in the hash fails. What's up?

Lost in the dawn of time, back in the Bronze age when the the HTML standard was first defined, the Powers That Be decided that developers would be interested not just in whether a graphic image (such as a button) was clicked, but also in the specific X-Y coordinates that were clicked.

Now, it's possible that this might be a useful feature for some web-based game, though it's hard to see how the X-Y coordinate of a click within a graphic button would be useful when image maps would probably be more effective at accomplishing the same objective.

Nevertheless, graphic buttons are handled a little differently than regular buttons. The params hash gets vaues for "confirm.x" and "confirm.y" if the Confirm button is clicked; each of those keys has as its value the X or Y coordinate, respectively, of the position within the button that was clicked. Armed with this information, the check for which image button was clicked becomes:

      if params['confirm.x']
         # Do something
      else
         # Do something else
      end

Again, information will only be sent for the particular image button that was clicked. If "confirm.x" has a value, then that was the button that was clicked.

The Third Iteration

Since I originally wrote this article in 2007, I've run into some situations where X/Y coordinates were not sent when forms have been submitted. The issue seems to be specific to certain browsers on selected platforms. I developed a solution for this problem, but it requires JavaScript and hence doesn't work if the user disables JavaScript in their browser.

The basic idea is that the image submit buttons have an onClick event defined. When clicked, JavaScript is executed to place a value in a hidden field indicating which button was pressed. At the server, the value of the hidden field can be examined to determine which button was clicked, and therefore which action should be performed.

   <% form_remote_tag(:url => {:action => 'myform'}, :update => 'result',
         :html => { :name => 'myform' } ) do %>
      <%= hidden_field_tag 'form_action' %>
      <%= image_submit_tag "button_confirm.gif", :name => "confirm", :onClick => "document.myform.form_action.value='confirm'" %>       <%= image_submit_tag "button_cancel.gif", :name => "cancel", :onClick => "document.myform.form_action.value='cancel'" %>
   <% end %>

The form shown above powers an AJAX change to a "results" div on the web page. When submitted, the "myform" action on the current controller is called (OK, we could have come up with a better name for the action but this is demonstration code). The hidden field technique allows the controller to make a decision as to which action to take..."cancel" or "confirm".



Comments

David Keener By Firrox on Tuesday, June 15, 2010 at 02:37 PM EST

By far the most elegant solution I've found. Thanks!


David Keener By wsc on Friday, August 27, 2010 at 07:01 AM EST

Thanks!


David Keener By ptyagi on Wednesday, October 10, 2012 at 04:32 PM EST

This was helpful. Well thought through. Thanks


Leave a Comment

Comments are moderated and will not appear on the site until reviewed.

(not displayed)