
- •Contents
- •Preface to the Second Edition
- •Introduction
- •Rails Is Agile
- •Finding Your Way Around
- •Acknowledgments
- •Getting Started
- •The Architecture of Rails Applications
- •Models, Views, and Controllers
- •Active Record: Rails Model Support
- •Action Pack: The View and Controller
- •Installing Rails
- •Your Shopping List
- •Installing on Windows
- •Installing on Mac OS X
- •Installing on Linux
- •Development Environments
- •Rails and Databases
- •Rails and ISPs
- •Creating a New Application
- •Hello, Rails!
- •Linking Pages Together
- •What We Just Did
- •Building an Application
- •The Depot Application
- •Incremental Development
- •What Depot Does
- •Task A: Product Maintenance
- •Iteration A1: Get Something Running
- •Iteration A2: Add a Missing Column
- •Iteration A3: Validate!
- •Iteration A4: Prettier Listings
- •Task B: Catalog Display
- •Iteration B1: Create the Catalog Listing
- •Iteration B4: Linking to the Cart
- •Task C: Cart Creation
- •Sessions
- •Iteration C1: Creating a Cart
- •Iteration C2: A Smarter Cart
- •Iteration C3: Handling Errors
- •Iteration C4: Finishing the Cart
- •Task D: Add a Dash of AJAX
- •Iteration D1: Moving the Cart
- •Iteration D3: Highlighting Changes
- •Iteration D4: Hide an Empty Cart
- •Iteration D5: Degrading If Javascript Is Disabled
- •What We Just Did
- •Task E: Check Out!
- •Iteration E1: Capturing an Order
- •Task F: Administration
- •Iteration F1: Adding Users
- •Iteration F2: Logging In
- •Iteration F3: Limiting Access
- •Iteration F4: A Sidebar, More Administration
- •Task G: One Last Wafer-Thin Change
- •Generating the XML Feed
- •Finishing Up
- •Task T: Testing
- •Tests Baked Right In
- •Unit Testing of Models
- •Functional Testing of Controllers
- •Integration Testing of Applications
- •Performance Testing
- •Using Mock Objects
- •The Rails Framework
- •Rails in Depth
- •Directory Structure
- •Naming Conventions
- •Logging in Rails
- •Debugging Hints
- •Active Support
- •Generally Available Extensions
- •Enumerations and Arrays
- •String Extensions
- •Extensions to Numbers
- •Time and Date Extensions
- •An Extension to Ruby Symbols
- •with_options
- •Unicode Support
- •Migrations
- •Creating and Running Migrations
- •Anatomy of a Migration
- •Managing Tables
- •Data Migrations
- •Advanced Migrations
- •When Migrations Go Bad
- •Schema Manipulation Outside Migrations
- •Managing Migrations
- •Tables and Classes
- •Columns and Attributes
- •Primary Keys and IDs
- •Connecting to the Database
- •Aggregation and Structured Data
- •Miscellany
- •Creating Foreign Keys
- •Specifying Relationships in Models
- •belongs_to and has_xxx Declarations
- •Joining to Multiple Tables
- •Acts As
- •When Things Get Saved
- •Preloading Child Rows
- •Counters
- •Validation
- •Callbacks
- •Advanced Attributes
- •Transactions
- •Action Controller: Routing and URLs
- •The Basics
- •Routing Requests
- •Action Controller and Rails
- •Action Methods
- •Cookies and Sessions
- •Caching, Part One
- •The Problem with GET Requests
- •Action View
- •Templates
- •Using Helpers
- •How Forms Work
- •Forms That Wrap Model Objects
- •Custom Form Builders
- •Working with Nonmodel Fields
- •Uploading Files to Rails Applications
- •Layouts and Components
- •Caching, Part Two
- •Adding New Templating Systems
- •Prototype
- •Script.aculo.us
- •RJS Templates
- •Conclusion
- •Action Mailer
- •Web Services on Rails
- •Dispatching Modes
- •Using Alternate Dispatching
- •Method Invocation Interception
- •Testing Web Services
- •Protocol Clients
- •Secure and Deploy Your Application
- •Securing Your Rails Application
- •SQL Injection
- •Creating Records Directly from Form Parameters
- •Avoid Session Fixation Attacks
- •File Uploads
- •Use SSL to Transmit Sensitive Information
- •Knowing That It Works
- •Deployment and Production
- •Starting Early
- •How a Production Server Works
- •Repeatable Deployments with Capistrano
- •Setting Up a Deployment Environment
- •Checking Up on a Deployed Application
- •Production Application Chores
- •Moving On to Launch and Beyond
- •Appendices
- •Introduction to Ruby
- •Classes
- •Source Code
- •Resources
- •Index
- •Symbols

Chapter 22
Action View
We’ve seen how the routing component determines which controller to use and how the controller chooses an action. We’ve also seen how the controller and action between them decide what to render to the user. Normally that rendering takes place at the end of the action, and typically it involves a template. That’s what this chapter is all about. The ActionView module encapsulates all the functionality needed to render templates, most commonly generating HTML, XML, or JavaScript back to the user. As its name suggests, ActionView is the view part of our MVC trilogy.
22.1Templates
When you write a view, you’re writing a template: something that will get expanded to generate the final result. To understand how these templates work, we need to look at three areas
•Where the templates go
•The environment they run in
•What goes inside them
Where Templates Go
The render method expects to find templates under the directory defined by the global template_root configuration option. By default, this is set to the directory app/views of the current application. Within this directory, the convention is to have a separate subdirectory for the views of each controller. Our Depot application, for instance, includes admin and store controllers. As a result, we have templates in app/views/admin and app/views/store. Each directory typically contains templates named after the actions in the corresponding controller.
You can also have templates that aren’t named after actions. These can be rendered from the controller using calls such as

TEMPLATES 466
render(:action => 'fake_action_name') render(:template => 'controller/name' )
render(:file |
=> 'dir/template') |
The last of these allows you to store templates anywhere on your filesystem. This is useful if you want to share templates across applications.
The Template Environment
Templates contain a mixture of fixed text and code. The code is used to add dynamic content to the template. That code runs in an environment that gives it access to the information set up by the controller.
•All instance variables of the controller are also available in the template. This is how actions communicate data to the templates.
•The controller object’s flash, headers, logger, params, request, response, and session are available as accessor methods in the view. Apart from the flash, view code probably shouldn’t use these directly, because responsibility for handling them should rest with the controller. However, we do find this useful when debugging. For example, the following rhtml template uses the debug method to display the contents of the session, the details of the parameters, and the current response.
<h4>Session</h4> <%= debug(session) %> <h4>Params</h4> <%= debug(params) %> <h4>Response</h4> <%= debug(response) %>
•The current controller object is accessible using the attribute named controller. This allows the template to call any public method in the controller (including the methods in ActionController).
•The path to the base directory of the templates is stored in the attribute base_path.
What Goes in a Template
Out of the box, Rails supports three types of template.
•rxml templates use the Builder library to construct XML responses.
•rhtml templates are a mixture of HTML and embedded Ruby. They are typically used to generate HTML pages.
•rjs templates create JavaScript to be executed in the browser and are typically used to interact with AJAXified web pages.
We’ll talk briefly about Builder next and then look at rhtml. We’ll look at rjs templates in Chapter 23, The Web, V2.0, on page 521.
Report erratum

TEMPLATES 467
Builder Templates
Builder is a freestanding library that lets you express structured text (such as XML) in code.1 A Builder template (in a file with an .rxml extension) contains Ruby code that uses the Builder library to generate XML.
Here’s a simple Builder template that outputs a list of product names and prices in XML.
Download erb/builder.rb
xml.div(:class => "productlist") do
xml.timestamp(Time.now)
@products.each do |product| xml.product do
xml.productname(product.title) xml.price(product.price, :currency => "USD")
end end
end
With an appropriate collection of products (passed in from the controller), the template might produce something such as
<div class="productlist" >
<timestamp>Sun Oct 01 09:13:04 EDT 2006</timestamp> <product>
<productname>Pragmatic Programmer</productname> <price currency="USD" >12.34</price>
</product>
<product>
<productname>Rails Recipes</productname> <price currency="USD" >23.45</price>
</product>
</div>
Notice how Builder has taken the names of methods and converted them to XML tags; when we said xml.price, it created a tag called <price> whose contents were the first parameter and whose attributes were set from the subsequent hash. If the name of the tag you want to use conflicts with an existing method name, you’ll need to use the tag! method to generate the tag.
xml.tag!("id", product.id)
Builder can generate just about any XML you need: it supports namespaces, entities, processing instructions, and even XML comments. Have a look at the Builder documentation for details.
1. Builder is available on RubyForge (http://builder.rubyforge.org/) and via RubyGems. Rails comes packaged with its own copy of Builder, so you won’t have to download anything to get started.
Report erratum

TEMPLATES 468
RHTML Templates
At its simplest, an rhtml template is just a regular HTML file. If a template contains no dynamic content, it is simply sent as is to the user’s browser. The following is a perfectly valid rhtml template.
<h1>Hello, Dave!</h1> <p>
How are you, today?
</p>
However, applications that just render static templates tend to be a bit boring to use. We can spice them up using dynamic content.
<h1>Hello, Dave!</h1> <p>
It's <%= Time.now %>
</p>
If you’re a JSP programmer, you’ll recognize this as an inline expression: any code between <%= and %> is evaluated, the result is converted to a string using to_s, and that string is substituted into the resulting page. The expression inside the tags can be arbitrary code.
<h1>Hello, Dave!</h1> <p>
It's <%= require 'date'
DAY_NAMES = %w{ Sunday Monday Tuesday Wednesday Thursday Friday Saturday }
today = Date.today DAY_NAMES[today.wday]
%>
</p>
Putting lots of business logic into a template is generally considered to be a Very Bad Thing, and you’ll risk incurring the wrath of the coding police should you get caught. We’ll look at a better way of handling this when we discuss helpers on page 471.
Sometimes you need code in a template that doesn’t directly generate any output. If you leave the equals sign off the opening tag, the contents are executed, but nothing is inserted into the template. We could have written the previous example as
<% require 'date'
DAY_NAMES = %w{ Sunday Monday Tuesday Wednesday Thursday Friday Saturday }
today = Date.today
%>
<h1>Hello, Dave!</h1> <p>
It's <%= DAY_NAMES[today.wday] %>.
Tomorrow is <%= DAY_NAMES[(today + 1).wday] %>.
</p>
Report erratum

TEMPLATES 469
In the JSP world, this is called a scriptlet. Again, many folks will chastise you if they discover you adding code to templates. Ignore them—they’re falling prey to dogma. There’s nothing wrong with putting code in a template. Just don’t put too much code in there (and especially don’t put business logic in a template). We’ll see later how we could have done the previous example better using a helper method.
You can think of the HTML text between code fragments as if each line were being written by a Ruby program. The <%...%> fragments are added to that same program. The HTML is interwoven with the explicit code that you write. As a result, code between <% and %> can affect the output of HTML in the rest of the template.
For example, consider the template
<% 3.times do %> Ho!<br/>
<% end %>
Internally, the templating code translates this into something like the following.
3.times do
concat("Ho!<br/>", binding) end
The concat method appends its first argument to the generated page. (The second argument to concat tells it the context in which to evaluate variables.) The result? You’ll see the phrase Ho! written three times to your browser.
Finally, you might have noticed example code in this book where the ERb chunks ended with -%>. The minus sign tells ERb not to include the newline that follows in the resulting HTML file. In the following example, there will not be a gap between line 1 and line 2 in the output.
The time
<% @time = Time.now -%> is <%= @time %>
You can modify the default behavior by setting the value of the erb_trim_mode property in your application’s configuration. For example, if you add the following line to environment.rb in the config directory
config.action_view.erb_trim_mode = ">"
trailing newlines will be stripped from all <%...%> sequences.
As a curiosity, if the trim mode contains a percent character, you can write your templates slightly differently. As well as enclosing Ruby code in <%...%>, you can also write Ruby on lines that start with a single percent sign. For example, if your environment.rb file contains
Report erratum

TEMPLATES 470
config.action_view.erb_trim_mode = "%"
you could write something like
%5.downto(1) do |i| <%= i %>... <br/>
%end
See the ERb documentation for more possible values for the trim mode.
Escaping Substituted Values
There’s one critical danger with rhtml templates. When you insert a value using <%=...%>, it goes directly into the output stream. Take the following case.
The value of name is <%= params[:name] %>
In the normal course of things, this will substitute in the value of the request parameter name. But what if our user entered the following URL?
http://x.y.com/myapp?name=Hello%20%3cb%3ethere%3c/b%3e
The strange sequence %3cb%3ethere%3c/b%3e is a URL-encoded version of the HTML <b>there</b>. Our template will substitute this in, and the page will be displayed with the word there in bold.
This might not seem like a big deal, but at best it leaves your pages open to defacement. At worst, as we’ll see in Chapter 26, Securing Your Rails Application, on page 599, it’s a gaping security hole that makes your site vulnerable to attack and data loss.
Fortunately, the solution is simple. Always escape any text that you substitute into templates that isn’t meant to be HTML. Rails comes with a method to do just that. Its long name is html_escape, but most people just call it h.
The value of name is <%= h(params[:name]) %>
Get into the habit of typing h( immediately after you type <%=.
You can’t use the h method if the text you’re substituting contains HTML that you want to be interpreted, because the HTML tags will be escaped—if you create a string containing <em>hello</em> and then substitute it into a template using the h method, the user will see <em>hello</em> rather than hello.
The sanitize method offers some protection. It takes a string containing HTML and cleans up dangerous elements: <form> and <script> tags are escaped, and on= attributes and links starting javascript: are removed.
The product descriptions in our Depot application were rendered as HTML (that is, they were not escaped using the h method). This allowed us to embed formatting information in them. If we allowed people outside our organization to enter these descriptions, it would be prudent to use the sanitize method to reduce the risk of our site being attacked successfully.
Report erratum