In the previous installment, we learned about two of Rails’ methods that help create forms, form_for and remote_form_for. Those methods dealt with forms primarily based on Model data. Today we’ll turn our attention to form_tag and form_remote_tag which create more generic forms not tied to Model data.

Tutorial after the jump…

As mentioned, form_tag allows you to create forms that aren’t tied to a particular Model in your Rails application. In our super simple example, we’re going to have a form consisting of a single text input control and a submit button. Whatever text is input will be displayed just below the form.

Here’s what our controller method looks like:

def form_tag_test
  @result = params[:text_to_display]
end

When called the first time the params array will be empty and @result will be nil.

Here’s our view:

<html>
  <head>
    <title>Form_Tag Test</title>
  </head>
  <body>
    <% form_tag( :action => :form_tag_test ) do %>
      <%= text_field_tag( :text_to_display, @params[:text_to_display] ) %>
      <%= submit_tag( "Display Text!" ) %>
    <% end %>
    <strong><%= @result %></strong>
  </body>
</html>

Like the other form methods we’ve seen in rails, form_tag wraps code within in a ruby block, but in this case we’re not using a form_builder object. Instead, we’ll use text_field_tag and its FormTagHelper ilk to build our form. Our simple prototype only has a text_field_tag, but you can see documentation on all of your choices here.

The second parameter of text_field_tag is the value in the params collection that the controller can find the entered value. Each XX_field_tag method will send it’s value in a different hash key. In this way, the controller will have access to every value in our form.

form_tag takes a parameter indicating which controller method to execute. In our simple case we’re just going to call the same method again. The documentation for url_for shows how to call other options on form_tag.

Our simple view concludes with a bit of ERb displaying the @result parameter. When the page is first viewed, this parameter will be blank and nothing will be shown.

When we post the form, the form_tag_test method is called in the controller. As we see in the code above, we read the value out of the params collection and put it into the @result variable. Then, when the view is redisplayed, we see the value we entered into the text box in bold type just below our form.

form_remote_tag is the worst named of the lot. If we have form_for and remote_form_for, why on earth don’t we also have remote_form_tag? I suppose even Rails needs to contribute its own bit of perversity into the universe. Of all the methods we’ve talked about so far, though, form_remote_tag is probably my favorite, since by definition it can do all kinds of fun AJAX stuff and it isn’t tied to any model data. We can use form_remote_tag for just about anything.

Here’s our form_remote_tag controller code:

def form_remote_tag_test
end

As you can see, all that it does is render the form_remote_tag_test.rhtml view:

<html>
  <head>
    <title>Form_Remote_Tag Test</title>
    <%= javascript_include_tag :defaults %>
  </head>
  <body>
    <% form_remote_tag :url => { :action => :remote_test }, 
                       :update => :results,
                       :complete => visual_effect(:highlight, 'results') do %>
      <%= text_field_tag( :text_to_display, @params[:text_to_display] ) %>
      <%= submit_tag( "Display Text!" ) %>
    <% end %>
    <div id='results'>
    </div>
  </body>
</html>

This is a bit more interesting than the form_tag view. First, notice that we’re including the default Rails javascripts up there in the head tag. This is important, because without it AJAX won’t work and you’ll usually get some weird output. Also notice that besides the form_remote_tag method call, the rest of our form looks exactly the same. The xx_field_tag methods work exactly the same as they did in form_tag, so we won’t mention them more here.

form_remote_tag looks a good bit like remote_form_for though. In fact, the only real difference is that we don’t need to reference a Model object. This time though we’re calling the remote_test method in the controller:

def remote_test
  @result = params[:text_to_display]
  render :partial => 'form'
end

Here we’re putting the text_to_display value from the params collection (which is the value entered into the text input control) into the @result variable and then we’re rendering the _form.rhtml partial. In form_remote_tag we indicated that we wanted to :update the DOM component called (with the id value of) :results. So, the contents of the _form.rhtml partial goes into the results div.

Here’s the partial:

<%= @result %>

So, all we’re really doing is writing whatever is in the text box into the results div. This would produce exactly the same result as the form_tag_test except for two things. First, since we’re getting AJAXy with it, the browser doesn’t reload the page. Second, the :complete => visual_effect(:highlight, ‘results’) parameter makes the ‘results’ div glow bright yellow and then fade back to white. It’s a very simple AJAX operation, but I think it illustrates the functionality pretty well.

Since I’ve been writing these tutorials and thinking about forms in Rails a good bit the past few days, the names have kind of grown on me. Other than form_remote_tag they don’t seem too horribly named. I now think of form_for as meaning “make a form for this particular Model object.” form_tag now seems pretty obvious – it creates an html form tag. Perhaps it’s just the lack of clear documentation that lead to my confusion.

My lesson, and maybe yours as well, to learn out of this is that when something is confusing, even if it’s something you’ve been using for a while, it is probably a good idea to break it down into a very simple working prototype. Then you may be able to grasp how it works, why it works, and maybe why the heck it’s named the way it is.

As always, thanks for reading, and please leave a comment if you have any questions at all. I’m no expert, but I’ll be glad to try to help. Please feel free as well to point out any errors I’ve made or rewrite sections of code that may need it.

I think my next topic will be how to integrate Google Checkout into your Ruby on Rails application. Hope to have it up soon!

10 Responses to “Forms in Ruby on Rails - Part 2”

  1. Shadowfiend Says:

    Another good one :)

    It bears mentioning that the various AJAX helpers (link_to_remote, form_remote_tag, remote_form_for, etc) generate inline Javascript, so they pollute your markup with Javascript. The UJS4Rails plugin (http://www.ujs4rails.com/) combats that by encouraging unobtrusive Javascript, giving you the ability to write unobtrusive scripts, and, conveniently enough, replacing the various remote helpers with ones that generate unobtrusive (and gracefully degrading) Javascript instead.

    Now that I look at it, they’ve put the `remote’ all over the place. link_to_remote is at the end, form_remote_tag is in the middle, and remote_form_for is at the beginning. Worse, there’s also a form_remote_for, but no remote_form_tag. Argh. Someone needs to go in and sort out that mess in the Rails API. Because I never use those helpers, I hadn’t realized before how darn ugly that zone of the API is.

  2. TAD Says:

    Aside from aesthetics, why would I want less obtrusive javascript?

  3. Shadowfiend Says:

    Graceful degradation, for one. The idea is that behavior is another layer on your site. Typically, a web page is viewed as two layers: the structure and the style, represented by (X)HTML and CSS. This adds the idea of another layer, the behavior, represented by Javascript.

    Graceful degradation is the idea that your site should work perfectly without Javascript, and, if Javascript is available, should just get some sprucing up. Thinking about things in the aforementioned terms typically helps in achieving that, just because the mindset is appropriate for that kind of design.

    So basically, because it keeps your markup purely structural, your styles purely stylistic, and your behavior behavioral.

  4. TAD Says:

    Ah, Ok. I think I see what you’re talking about. The only problem is that you have to draw a line at some point. We already have MVC. It sounds like you’re talking about MVCB, and I don’t have a problem with that.

    However, I bet someone could come up with yet another logical division. Say, dividing behavior into subgroups ending up in MVCBL or something. And that rabbit hole probably keeps going on forever. :)

    Not to say that what you’re suggesting is a bad idea, but I’ve worked on lots of stuff where layers and terminology end up creating too much work and ultimately leaving apps difficult to maintain.

    Regardless, I’ll take a look at unobtrusive javascript – I’m pretty sure I have some bookmarks in delicious on it.

  5. Shadowfiend Says:

    It’s not really an extension to MVC. MVC is a programmatic construct more easily used on the server side. This is more of a client-side browser thing. Structure and style are two layers whose separation has been encouraged more recently. We used to blend them nastily with tables, then we wised up and started using CSS, but would still mix them in the same file, and then we separated them completely with external stylesheets and such. This is taking that same idea and applying it to Javascript.

    And its biggest boon is really, like I said, in that it enforces a pattern of thinking that facilitates progressive enhancement/graceful degradation.

  6. TAD Says:

    Right – I get the distinction. My point was that someone can always argue into existence another, previously unthought of layer, and after enough layers things become over complicated.

    Web development already has plenty of layers from the database up to the presentation and behavior in the client.

    I think I’m just cautioning against too much separation. Someone may argue that we need a seperate css-like file to handle all of the “coloring” on a webpage, where someone else may want to split javascript behavior into files based on “user initiated” and “server initiated (AJAX callbacks)” behaviors. At some point it just gets absurd.

  7. chriso Says:

    These are great – I’ve always felt shamed out that I get the form syntax so horribly wrong.

    These articles are a big help!

    -Chris

  8. Srdjan Says:

    Great article, first of all. As to the unobtrusive JavaScript debate, there’s also one more component to think about, accessibility. A screen reader will be able to better read your website to a blind user, if JavaScript was not intermixed with HTML code. To me, above all other points, such as separation of concerns and elegance, this speaks the loudest. Just how including ALT attributes to image tags is a good practice, so is separating JS from HTML. I will as well look at the plugin. Shadowfiend, the plugin does not affect how you declare your Ajax Rails tags, right?

  9. Mike B. Says:

    Have you ever used form_tag along with a link_to to submit the form? I’ve seen it work with PHP apps, but not sure how to get it done in a rails type environment.

  10. David Allen Says:

    Maybe I’m too new to ruby, but I did your example and I do not get a result. My form is called find.rhtml and the controller is find_controller.rb. Can you spot any obvious errors? Oh, and I do love the tutorial.

    Thanks, Dave

    as:

    Find#find

    Find me in app/views/find/find.rhtml

    <!DOCTYPE HTML PUBLIC ”-//W3C//DTD HTML 4.01//EN”> <%= error_messages_for ‘find’ %> <html> <body> <% form_tag( :action => :find ) do %> <%= text_field_tag( :myID, @params[:myID] ) %> <%= submit_tag( “Display Text!” ) %> <% end %> <%= @result %> </body> </html>

    class FindController < ApplicationController def form find @result = params[:myID] end end

Sorry, comments are closed for this article.