Forms
Lecture Notes for CS 142
Fall 2010
John Ousterhout
- Readings for this topic:
- Chapter 20 of Agile Web Development with Rails,
plus Sections 23.4-23.8.
Form basics
- HTML mechanism for user input
- A collection of HTML elements
- A protocol for communicating data to the server
- Form:
- Collection of elements
- Each element has a name and a value (strings)
- Different types of elements provide different ways
for the user to edit the value (text entry, checkbox,
menu, etc.)
- Simple form example:
<form action="/x/y/z" method="POST">
Value1: <input type="text" name="value1"/><br />
Value2: <input type="text" name="value2" value="47"/><br />
<input type="submit" value="Submit"/>
</form>
- <form> element: overall container for form elements
- action specifies a URL to invoke when the form is submitted.
- method attribute indicates which HTTP method to use when
communicating with the server; defaults to GET but should
always be POST (GET limits size of posted data)
- Arbitrary HTML OK inside <form>
- Can have more than one form in a page
- <input> elements: controls for entering data.
- type attribute specifies which of several controls to use.
text is a simple one-line text entry.
- name attribute: used to identify this particular value
when posting form to server.
- value attribute specifies initial value for this element.
- <input type="submit"> creates a button for submitting the form.
- value attribute specifies text to display in button.
- Other form elements: see
formElements.html for examples.
- When the submit button is clicked:
- HTTP POST request is made to the URL given by the action attribute
of the <form> element.
- Body of the request contains name-value pairs from the <input>
elements, URL-encoded (looks like query data in a URL).
- Result is an HTML page that replaces the form page.
- On the server side:
- Like any other HTTP request.
- Rails makes the form data available through the params hash.
Form flow
- Problem #1:
- Consider an ordering system:
- One or more pages of forms
- Final form to confirm order
- "Thank you for your order" page
- Use Back button to return to the thank-you page
- Solution:
- One URL displays form
- POST goes to a second URL
- Redirect after POST:
- POST page doesn't generate HTML
- After redirection, POST URL disappears from browser history list
- Divide URLs:
- Those that display information (including forms) (GET method)
- Those that invoke modifications (POST method)
- Don't mix these two
- Problem #2:
- Invalid form data detected by server during POST
- Desired effect:
- Redisplay the form page
- Display error messages about the problems (ideally,
display messages next to the offending form elements)
- Retain all of the data that the user entered in
the form
Rails form support
- Ties in nicely to the ORM system
- One model object holds one database record
- Form used to edit part or all of a record
- Form helpers: methods to generate HTML elements for
forms: you don't have to write HTML directly.
- Validation: mechanism for detecting errors in input
data.
- Form helpers example (student record):
- Controller:
@student = Student.find(params[:id])
- View:
<% form_for(:student, :url => {:action => :modify,
:id => @student.id}) do |form| %>
<table class="form">
<tr>
<td class="label">Name:<td>
<td><%= form.text_field(:name) %><td>
</tr>
<tr>
<td class="label">Date of birth:<td>
<td><%= form.text_field(:birth) %><td>
</tr>
<tr>
<td class="label">Grade-point average:<td>
<td><%= form.text_field(:gpa) %><td>
</tr>
<tr>
<td class="label">Graduation year:<td>
<td><%= form.text_field(:grad) %><td>
</tr>
<table>
<%= submit_tag "Modify Student" %>
<% end %>
- :student argument to form_for: identifies
both the model class and the name of a variable containing
data
- :url argument to form_for: URL where
form will get posted
- form.text_field: returns an HTML input
element of type text, provides initial value
from corresponding attribute of @student:
<input id="student_name" name="student[name]" size="30"
type="text" value="Wendy Wilson" />
- Handling post:
def modify
@student = Student.find(params[:id])
if @student.update_attributes(params[:student]) then
redirect_to(:action => :show)
else
render(:action => :edit)
end
end
- Form data automatically available in params:
nested hash named after the form.
- update_attributes copies values from the form data
into the model object and saves the model object.
- Error handling in Rails forms:
- Validation:
class Student < ActiveRecord::Base
def validate
if (gpa < 0) || (gpa > 4.0) then
errors.add(:gpa, "must be between 0.0 and 4.0")
end
end
validates_format_of :birth, :with=> /\d\d\d\d-\d\d-\d\d/,
:message => "must have format YYYY-MM-DD"
end
- Validation methods get invoked whenever the object
is saved.
- errors.add saves an error message related to
a particular attribute of the object.
- Several built-in validators, such as validates_format_of.
- If there is a validation error, methods such as save and
update_attributes abort and return false.
- After a validation error, the action method explicitly
re-renders the form.
- Form helpers:
- error_messages_for generates HTML for all the error
messages for an object
- form.text_field and similar methods add an extra
<div class="fieldWithErrors"> around any form elements
for which there are error messages: use CSS to display
differently.
File uploads with Rails
- If you use <input type="file">, then you must request
a different protocol for posting data:
<form method="POST" enctype="multipart/form-data">
- Rails knows how to handle this format (some frameworks don't):
- Normal form data available in the normal way
- Siphons off uploaded files to files on disk; the
params value for this form element is an object
with lots of methods.
- In Rails, add an extra argument to the form_for method:
form_for(... :url => {...}, :html => {:multipart => true})
- Form helper to generate form element:
- read method: returns contents of uploaded file.
- original_filename method: returns file name as selected
in the browser.