At the beginning stages of any new framework or language, you can get away with just posting stupid-programming tricks. This was the case with Ruby and Rails. It was fairly new about a year or two ago, but now, it's pretty much old hat, so I sometimes don't bother posting things that I figure out, since I figured it's old news.
Except, I'm still discovering little things here and there. It's not just with the new fancy RJS templates either. Old favorites like
link_to_remote() still have unexplored corners (which we'll get to in a minute). Although this one wasn't that painful, I found it as a footnote in the Rails documentation, that others might have easily missed.
So the answer to the common question I was looking for was "How do I have two submit buttons in the same form?" Usually, we need this when there is a set of user-entered data that has more than one action associated with it. For example, in a blog editing page, you usually want to do two things: "save as draft" or "publish". And when you think about it, the file system on your desktop operates with the same metaphor. You select a bunch of files (the user-data), and right-click to select an action (move, copy, delete, etc).
So with a normal form submission, there is
the solution of just naming the submit tags, and since the submit button will submit its value along with the form, you can tell which button was pressed:
<%= start_form_tag :action => :post %>
<%= submit_tag "Save", :name=>"save" %>
<%= submit_tag "Preview", :name=>"preview" %>
<%= end_form_tag %>
And then, in your controller, you simply check whether params["save"] or params["preview"] exists, and do the appropriate action, or call the appropriate callback.
def post
if params["save"]
save
render :action => :save
else
preview
render :action => :preview
end
def save
# do saving stuff
end
def preview
# do preview stuff
end
Cake, right? But what if you wanted to do this with a form submitted by XML_HTTP_REQUEST? This hack doesn't work with form_remote_tag, since it serializes the entire form, regardless of which buttons was pressed. I was all ready to buckle down and really learn some javascript, instead of the bits and pieces that I know.
But after combing through the documentation, apparently someone on the Rails team needed to do something similar before. If you look at the very end of the documentation for link_to_remote(), you'll find this:
:submit: Specifies the DOM element ID that‘s used as the parent of the form elements. By default this is the current form, but it could just as well be the ID of a table row or any other DOM element.
It ends up that you can use this to serialize anything containing form elements. But not only that, there are two other bonuses.
One, you can stylize the submit links to look far better than the ugly submit buttons. Two, you no longer need a dispacher method. Each link_to_remote "submit button" routes to its respective actions, which means you can have way more than two submit buttons, and not have a gigantic "if elsif" statement in a dispatcher method in your controller. Neat.
<div id="image_collection">
<% @images.each do |image| %>
<%= check_box "selected_images", image.id %>
<%= image_tag image.path %>
<% end %>
<%= link_to_remote "Group", :url => { :action => :group }, :submit => :image_collection %>
<%= link_to_remote "Delete", :url => { :action => :delete }, :submit => :image_collection %>
</div>
Notice that the parent tag doesn't have to be a form. It can be a div.
One downside to this is design related. Because the link_to_remote call can be anywhere on the page, unlike a submit button which has to be inside a form tag, one can put it anywhere. This added flexibility means that you have to be careful to put the newly minted submit button where it is obvious and intuitive that it submits the intended data. But if you're aware of that, have fun with your new and shiny multiple action form.
Update:
If you use :confirm in conjunction with :submit, make sure :confirm is in front of submit, as order seems to make a difference here.