Forms
Lecture Notes for CS 142
Spring 2013
John Ousterhout
- Additional reading for this topic:
- Goals for forms:
- Display information in an editable form
- Upload changes to the server
- Form:
- Collection of elements, each of which has
- Name (used by application, often invisible to user)
- Value
- User interface
- Different types of elements provide different ways
for the user to edit the value (text entry, checkbox,
menu, etc.)
HTML Form Support
- Simple form example:
<form action="/product/update" method="post">
Product: <input type="text" name="product"/><br />
Price: <input type="text" name="price" value="49.95"/><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 almost
always be POST (GET limits size of posted data)
- Arbitrary HTML OK inside <form> (e.g., decorations)
- 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.
Issues With Forms
- Problem #1: page flow
- Consider an order entry 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: error handling
- 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])
- Simple view:
<%= form_for(@student, :url => {:action => :update, :id =>@student.id}) do |form| %>
<%= form.text_field(:name) %>
<%= form.text_field(:birth) %>
<%= form.text_field(:gpa) %>
<%= form.text_field(:grad) %>
<%= form.submit "Modify Student" %>
<% end %>
- @student argument to form_for: object whose
contents are to be displayed in the form
- :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" />
- Can also mix other templating stuff in with form elements to
control formatting and provide other information:
<%= form_for(:student, :url => {:action => :update, :id => @student.id}) do |form| %>
<table class="form">
<tr>
<td class="label"><%= form.label(:name, "Name:")%><td>
<td><%= form.text_field(:name) %><td>
</tr>
<tr>
<td class="label"><%= form.label(:birth, "Date of birth:")%><td>
<td><%= form.text_field(:birth) %><td>
</tr>
<tr>
<td class="label"><%= form.label(:gpa, "Grade-point average:")%><td>
<td><%= form.text_field(:gpa) %><td>
</tr>
<tr>
<td class="label"><%= form.label(:grad, "Graduation year:")%><td>
<td><%= form.text_field(:grad) %><td>
</tr>
<table>
<%= submit_tag "Modify Student" %>
<% end %>
- Handling posts:
def update
@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
validates_format_of :birth, :with => /\d\d\d\d-\d\d-\d\d/,
:message => "must have format YYYY-MM-DD"
def validate_gpa
if (gpa < 0) || (gpa > 4.0) then
errors.add(:gpa, "must be between 0.0 and 4.0")
end
end
validate :validate_gpa
end
- Validation methods get invoked whenever the object
is saved.
- Several built-in validators, such as validates_format_of.
- Can also define custom validators, such as validate_gpa.
- errors.add saves an error message related to
a particular attribute of the object.
- 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.
- In the form view, extract and render all of the error messages
for the object:
<% @student.errors.full_messages.each do |msg| %>
<p><%= msg %></p>
<% end %>
- Form helpers:
- form.text_field and similar methods add an extra
<div class="field_with_errors"> around any form elements
and labels 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">
- Form helper to generate form element:
- Rails will automatically add enctype="multipart/form-data"
to the form element.
- Rails knows how to handle this format (some frameworks don't):
- Normal form data available in the normal way
- Siphons off uploaded file to a file on disk; the
params value for this form element is an object
with lots of methods.
- read method: returns contents of uploaded file.
- original_filename method: returns file name as selected
in the browser.