Table of Contents

Lesson Page

Download

Play


Sign Up Now!

If you aren’t already receiving our course lessons via email, sign up now to be sure you don’t miss anything.

Every few days, we’ll send you an email with a link to the next episode, plus a list of additional resources for advancing your knowledge.

There’s no cost and no obligation. And we’ll never share your email address with any third party.


We’ll send you the first lesson right away.


Want to help spread the word? We’d be grateful if you would include a link to the course in your blog, web site, or emails.

Rails Form Processing

comments

In previous episodes, we’ve described how the model, view, and controller work together to create web pages. Now we’re going to explore a more complicated example: displaying a form that the user completes, validating the submitted data, displaying error messages if there’s a validation failure, and storing the information in the database if it passes validation.

As in past episodes, we’re going to focus on the concepts and avoid actual code. Once you understand the concepts, it’s a lot easier to learn the coding specifics.

CRUD

Whatever information you’re storing in a web application’s database, whether it is products, transactions, podcasts, books, or contact information, you’re probably going to need to do four basic things with it, which go by the lovely acronym of CRUD: create, read, update, and destroy.

You may more naturally think of these operations as making a new database record, using that information, editing the record, and deleting it. That’s CRUD, said a little differently.

If a user is entering information in a web application, it’s probably in an HTML form. So forms play a big part in most Rails applications. To facilitate this nearly universal need, Rails provides an abundance of helpers that make form coding and processing about as simple as it can be.

Writing Form Views

You could write your own HTML form code and put it in a Rails view file, but Rails provides a much simpler alternative: a rich set of form helpers that enable you to create virtually the entire form in Ruby code, with Rails worrying about creating appropriate HTML.

At the start of a form, you use a helper called form_for, and then you provide the name of the object whose values are being set by the form. Using just the name of this object, Rails will figure out what controller to use (by appending “controller” to the pluralized name of the object).

So “form_for podcast” creates the start of a form for entering the podcast information. The submit URL will automatically be directed to a controller named podcasts_controller, specifying either the “create” action, if it is a new record, or the “update” action, if modifying an existing record.

So suppose you have a database of podcast episodes. The form starts with:

form_for @podcast

(The @ symbol before the name indicates that this is an instance variable, which is created by the controller for the view’s use.)

Then you create the fields that you want to display, using helpers with names like text_field, text_area, radio_button, select, and so forth. For each field, you specify one attribute of the model (which, you’ll remember, was specified in the form_for tag). So you might define a text_field for the podcast title, and a text_area field for the podcast description.

You can create your entire form without writing a bit of HTML code. In the real world, you’d typically want to wrap each form elements in some HTML element, perhaps a paragraph, or a div, or a table cell, so your view file will have simple HTML tags wrapping the form field helpers.

More complex forms

As long as your form consists of all or some of the fields for a single model, the code is supremely simple. If you need to draw from multiple models, such as getting a person’s address from one model while the person’s name comes from another, it’s only slightly more complex; there’s a helper called fields_for, which allows you to specify fields that come from any model.

Suppose we have another model called Link and the links table stores links associated with a particular podcast. After the form_for block, which starts the form for the podcast, you might have some podcast fields, and then you’d have a fields_for links helper. Within the fields_for block, you specify the fields that are associated with that model.

Forms get somewhat more complex when you have multiple instances of one model in a single form. For example, a customer profile form might allow multiple addresses to be entered, each of which creates an instance of the address model.

When you display the form, you want to list each of those instances, of which there may be a variable number, and allow them to be edited.

The specifics of how to do this are beyond what we can cover in this podcast, but suffice it to say that it’s a bit more complex than a basic form, but not fundamentally difficult.

Another common behavior in a form is to have certain fields come and go depending on the state of other fields. For example, you may want the shipping address fields to appear only if a check box labeled “use shipping address” is selected. We discussed how this sort of thing works back in episode 3.

What happens when a form is submitted

When the user clicks submit on a form, Rails invokes either the create (for a new record) or update (for an existing record) action in the associated controller. Forms are, by default, submitted with an HTTP POST command, and all the information that was entered in the form is provided in a hash called params, which is available to the controller.

A hash, as you may remember from episode 2, is a set of key-value pairs. Think of it as a set of named items, with the keys being the names. The value can be any Ruby object; it could be another hash, for example, which turns out to be how form data is passed.

The params hash includes, for each model used in a form, a hash whose name is the name of the model. For example, if the model is podcast, there will be a hash named podcast in the params hash. Within this podcast hash are key-value pairs for each of the fields in the form.

For simple forms, you don’t actually need to understand any of this. Rails is all set up to create and update objects based on the information in the params hash, so all you have to do is point Rails to the hash and tell it (using a few lines of Ruby in the controller) to save or update the corresponding record.

If your form has data from multiple models, the params hash will include multiple hashes, one for each model. If there are multiple instances of a single model, there will be an array of hashes for that model. Depending on the situation, you may need a little Ruby code in the controller to process data from multiple models.

It is possible to submit form data using an HTTP GET instead of POST. You can specify this as an option in the form_for helper that begins the form. If you do so, then all of the parameters appear in the URL when the form is submitted, which is generally undesirable.

Submitting a form with a GET operation is typically used for search forms. By using a GET to submit the form, the user can bookmark the results page, and going back to that bookmark will resubmit the search query, since the URL contains the entire search specification as query-string parameters (for example, mysite.com/search?subject=“Ruby on Rails”).

Processing form data in the controller

The create action, by convention, deals with creating new records from form submissions. It doesn’t have to do much; at its most basic, the create action needs only one line of code. Continuing with our podcast example, we could write:

Podcast.create params[:podcast]

Invoking the create method on the podcast model creates a new podcast object and then saves it to the database. You need only to pass the podcast hash to the create method, since this hash has all the data from the form fields relevant to that model. No matter how many fields you might have in your form, it’s just one simple line of code for each model.

Adding validations

In the real world the controller code for the create action is a little more than just a create statement, primarily because you generally want to validate the data from the user before storing it in the database. For example, we don’t want to store a podcast record if the title is blank.

Where should we validate the data? It could be done in the controller, but the right place to do this is in the model. You want validations to occur there because you want them to apply to any possible way data might be submitted. For example, it might come in via a web service call, as well as through a form.

As we discussed in episode 4, there’s a rich set of validation helpers, and you can write your own validations as well. In the simple case of wanting to ensure that our new podcast has a title, we’d write in the podcast model:

validates_presence_of :title

That’s simple enough, but what happens when it fails? The create method will return false in this case, signaling to the controller that the data was not saved. In this case, the controller should cause the form to be displayed again, with validation error messages, and with the erroneous fields highlighted.

Rails does all of this almost magically. In the controller, you need code that essentially says:

  • If the record was successfully created, then continue (in which case you might want to go to the list of podcasts, for example, or to a page that shows the current podcast).
  • If the record was not successfully created (in which case, the podcast.create method returned false), then redisplay the form.

This actually takes many fewer words in actual Ruby code:

if Podcast.create params[:podcast]
    redirect_to (wherever you want to go after a successful save)
else
    render :action => :new
end

Displaying validation errors

If any of the validations fail when attempting to save an object to the database, the model returns an array of error messages. You don’t have to do anything other than to define your specific validations; the ability to generate error messages is part of the rich set of capabilities that your models gain from ActiveRecord.

In your view, you need to do two things: display the validation errors, and highlight the fields in which those errors occurred. I hope it is not a surprise by now that Rails provides helpers that make this trivial.

To display the error messages, all it takes is a call to the error_messages_for helper, specifying the name of the object for which you want to display the message. So our podcast form would have a line that reads:

error_messages_for :podcast

This helper creates the HTML for a box that shows the messages. Rails provides default CSS, which you can of course modify, to put the messages in a red box.

To highlight the affected fields, Rails automatically wraps the fields for which there are errors in a div with a CSS class applied. The default Rails CSS applies a red background to such fields.

You can provide complete error message text as part of your validation code, if you’d like. If you don’t, Rails automatically creates a message based on the name of the attribute and the type of validation used.

For example, our podcast model has a validation that says the title cannot be blank, so Rails will create an error message that says just that: “title cannot be blank”.

If the fields in the form draw from multiple, different models, you can simply include each of their names when you invoke the “error_messages_for” helper. It’s a little more complicated if you have multiple instances of a single model in a form; it takes a few lines of Ruby in the controller to collect the error messages in a reasonable way.

Ajax forms

With a standard form submission, you’re navigating to a new page. If you want to redisplay the page the form was on, such as when adding a comment to a blog post, the user has to wait while all the information that is already on their screen is fetched from the server again.

You can streamline this experience using Ajax forms. With an Ajax form, submitting the form does not trigger a new page. Instead, an XML HTTP request is sent to the server. The form data is sent as POST data, just as for a normal submit, but the page that the user was on remains unchanged, at least for the moment.

The XML HTTP request is directed to a controller action much like the create or update action that processes a standard form submission. After saving (or attempting to save) the object, the controller invokes a view that returns just a snippet of HTML, rather than an entire page, to the browser.

What does the browser do with this bit of HTML? It updates a DOM element (that is, a piece of the page), whose ID was specified in the XML HTTP request. For example, you might include an empty div, with the id of “new_comment”, in the form. When the result from the XML HTTP request comes back, the div is automatically updated to include that HTML.

If you want to update more than one DOM element when the form submission is processed, the view that is triggered by the create or update action can return JavaScript, instead of HTML. Such JavaScript can make any modifications to the page that you want.

You can write the view that is invoked by the create or update action using Ruby JavaScript (RJS), enabling you to specify what happens to which DOM elements using pure Ruby code. Rails creates JavaScript from this Ruby code, and returns that JavaScript to the browser in response to the XML HTTP request.

Returning to our blog comment example, you could use RJS to modify two page elements when a new comment is submitted, deleting the comment form and updating the list of comments displayed to include the new comment.

Implementing Ajax forms

An Ajax form involves a fairly complex series of interactions, and if you were to write all the JavaScript yourself, it would involve a dramatic increase in the complexity of your forms code. Rails provides helpers, of course, that make it simple.

There’s a “remote_form_for” helper that you can use in place of “form_for”, and that’s all you have to do to cause the submission to be done via an XML HTTP request. Rails creates the JavaScript code, using the Prototype framework, that implements the request.

Just as with a regular form submission, you need to write a little bit of Ruby code in the controller, and HTML code in the view, to support handling of validation errors that may occur.

There’s some other related facilities in Rails that we don’t have time to explain fully here, but we’ll mention them so you can investigate further if they’re of interest.

  • As an alternative method of Ajaxifying a form, there’s a “submit_to_remote” helper that you can use in place of the normal submit helper. With this approach, you use a normal form_for, rather than remote_form_for.
  • There’s a “link_to_remote” helper that you can use anywhere, without needing a form at all, to make an Ajax request.
  • You can use the Scriptaculous effects to animate the changes to the page, which can be important for usability.
  • You can specify actions to be performed when certain events occur during the processing of a request. For example, you’ll typically want to display a spinner icon to show that the server is working when the request is sent, and then hide it when processing completes.

Summary

In this episode, we’ve explored how a diverse assortment of Rails helpers and other facilities make it easy to create and process forms to enter information into your database, and to modify information that is already there.

The form_for helper handles the setup for your form, creating the required HTML and directing the submission to the appropriate controller action. Helpers for each of the various field types create the form fields themselves.

Helpers in the model make validating form data easy, and view helpers take care of displaying messages and highlighting fields that have errors. And by using remote_form_for, you can implement Ajax forms almost as easily as conventional forms.

In our next episode, we’re going to talk about development practices that are part of the Ruby on Rails ecosystem, including source code control, deployment, documentation, and debugging.


Add a Comment

Have a comment or question about this lesson? Add it here.






Comments on This Lesson

From: Kevin Naidoo       Date: 11/19/08 08:20 PM

Subject: Speed and Crawl Impact

I am a newbie to ruby on rails so i don’t know if this makes sense ,but i have picked two general concerns:

Firstly with the whole controller and router concept, does this not mess up SEO? (possibly confuse web crawlers such as googlebots)

Secondly i don’t understand this concept of “slower speed for faster development cycle” , i am not sure how RoR servers work but in the case of shared hosting for example where you have 100’s of web sites utilizing the same server or a high bandwidth site(online gaming) will this not cause a great deal of inefficiency ?

From: Ibrahim        Date: 09/27/08 11:23 PM

Subject: create vs new

The difference between create and new is:
New means create a new Model instance so that you can manipulate data, but it will not be saved to the database (until you call the save method).

Example 1#
Open up ruby console (ruby script/console)
post = Post.new do |p|
p.title = “First post”
end

  1. => now it will give you a hash of information that’s ready to be send to the database
    Now it is not saved, but with this line it will:
    post.save

Create does the same as new, it creates a new instance of the Model, but it will also save it to the database.

I think the guys here used it because they needed an instance of the Model to build up the form. What I don’t get is: why use two methods if it can he handled in just one ?!

From: David Pickens       Date: 05/12/08 08:08 AM

Subject: Thank you..

I have studied dozens of tutorials / books, and none of them explained the difference and interplay between new and create. I was shaking my shaggy head for many many hours over this, analyzing restful_authentication, and couldn’t understand what the session new method did (nothing it seemed) and where create was used!

A pretty important basic concept I think. Thank you for helping this n00b! :)

From: Steve       Date: 05/07/08 09:09 AM

Subject: that helps...

…a little anyway. :) Seeing ”podcast=Podcast.new” duplicated in both actions is proving to be hard for me to comprehend. I gather that in the case of “new” that line establishes an intentionally temporary reference (what you call an “empty object”) so that “form_for” knows what “for” is. In the case of the “new” action the @podcast variable is needed to set the key for the hash, right? Because it seems that all “create” needs in order to create and attempt to save the object is the contents of the:podcast hash. I guess my confusion boils down to ”podcast” being declared in 2 places for different purposes.

Oh – I noticed one small typo in the notes on this page (not the transcript). You have a “has” where you meant “hash” in the line that reads:

“The create method takes the parameters from the params[:podcast] has”

Thanks Michael.

From: Michael Slater       Date: 05/06/08 09:21 PM

Subject: New vs. Create

The New action prepares the form for display; the Create action processes the data that was entered and attempts to save it to the database. If it doesn’t succeed, it displays the New form again with the previously entered data and the validation error messages. (One potentially confusing bit of syntax: the line “render :action => :new” renders the view file associated with the new action but does not execute the action itself.) The New action sets up an empty object, whereas the Create action makes an object with the data from the form. When you get to the screencast lessons (starting at lesson 9), you’ll see a full code example which should help clarify this.

From: Steve       Date: 05/06/08 12:12 PM

Subject: new vs. create

Can you clarify for me the difference between “new” and “create”? Both actions seem to start off by initialize a new variable (”@podcast=Podcast.new” in this case). “New” just generates the form (and the reference to @podcast), which “Create” then uses to attempt to save to the database using the data in the hash that has been populated by the form set up by “New”? I’ve read a bunch of stuff and watched a bunch of stuff and I still don’t feel I have a grasp of the interplay between new and create. Thanks!

 

Sponsored By

New Relic Rails Performance Monitoring

Peepcode Screencasts