Rails Introduction: Templates and Controllers
Lecture Notes for CS 142
Fall 2010
John Ousterhout
- Readings for this topic:
- Chapters 1-9 of Agile Web Development with Rails
provide an overview of all of the Rails facilities.
- Chapters 21-22 and Sections 23.1-23.3 and 23.9 of
Agile Web Development with Rails cover the
material of this topic in detail.
History of Web Frameworks
- Initially: static HTML files only.
- CGI:
- Certain URLs map to executable programs
- When URL is referenced, program runs
- Program's output is returned as the Web page
- Program exits after Web page complete
- Introduced the notion of stateless servers: each
request independent, no state carried over from previous
requests.
- Perl typically used for writing CGI programs
- First-generation frameworks (PHP, ASP.net, Java servlets):
- Incorporate language runtime system directly into Web server
- Templates: mix code and HTML
- Web-specific library packages:
- URL handling
- HTML generation
- Sessions
- Interfacing to databases
- Second-generation frameworks (Ruby on Rails, Django):
- Object-relational mapping: simplify the use of databases
(make database tables and rows appear as classes and objects)
- Model-view-controller: stylized decomposition of applications.
Overview
- Rails: a Web application framework based on the Ruby language.
Often referred to as "Ruby on Rails".
- Rails applications have an MVC (model-view-controller) structure:
- Model: manages the application data
- Each class encapsulates the data in a particular database table.
- View: generates Web page.
- Controller: glue between the model and view:
- Responds to incoming HTTP requests
- Fetches/modifies data in the models
- Invokes view(s) to render results
- The MVC pattern has been around since the late 1970's; originally
conceived in the Smalltalk project at Xerox PARC.
Templates
- Templates:
- The most common way to generate dynamic HTML; available in virtually
all Web development frameworks.
- Simple Rails example:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Hello, User</title>
</head>
<body>
<p>
This page was fetched at <%= Time.now() %>
</p>
</body>
</html>
- Basic ideas:
- Write HTML document containing parts of the page that are
always the same.
- Add bits of code that generate the parts that are computed for each page.
- The template gets expanded by executing code snippets,
substituting the results into the document.
- Benefits of templates:
- Easy to visualize HTML structure
- Easy to see how dynamic data fits in
- Two kinds of annotation in Rails templates:
- <%= ... %>: substitute value of expression
- <% ... %>: execute Ruby code, but no substitution of
result: use
concat
in code to generate HTML
- Can interleave Ruby control structures with HTML:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Rails Parameters</title>
</head>
<body>
<p>
The <code>params</code> hash contains the following values:
</p>
<% params.each do |key, value| %>
<p><%= key %>: <%= value %></p>
<% end %>
</body>
</html>
- Useful "helper" functions for Rails templates:
- h: method to escape special HTML characters.
- link_to: convenient for generating links; see pages 514-518
in the Rails book. Example:
<%= link_to(@name, {:action => "userInfo", :id => @user_id}) %>
- Including stylesheets or Javascript:
<%= stylesheet_link_tag "styles" %>
<%= javascript_include_tag "file1", "file2" %>
Controllers
- Most interesting Web pages require non-trivial amounts of code:
- Selecting/organizing data
- Business logic
- Putting all this in the template would make it illegible.
- Instead, put most code in controller, all template does is
substitute values into HTML.
- Lifecycle of an HTTP request:
- Dispatching:
- Rails receives incoming request
- Rails invokes a method in a Controller class, based on the
URL:
- Default: URL /rails_intro/hello will be dispatched to method
hello in class RailsIntroController. The controller
should be defined in the file
app/controllers/rails_intro_controller.rb
- You can define other mappings.
- The controller method corresponding to a URL is called an
action method.
- Controller can have several action methods; typically a controller
manages a related group of URLs.
- Rails makes URL information available to action methods:
- params holds query values
- If the URL had the form
/class/method/id
,
where id is an integer, then that value is available through
params[:id]. Commonly used to hold the primary key for
a database record to display the page.
- Controller action method:
- Collects data needed to generate the page, saves in
instance variables of the controller object.
- Typically does this by calling Model classes.
- By default, Rails automatically invokes the view once the
controller action method returns.
- For URL /rails_intro/hello, view file is
app/views/rails_intro/hello.html.erb
- Controller can override this by invoking render explicitly.
- Example: controller to compute primes:
class RailsIntroController < ApplicationController
def showPrimes
# Query value "count" indicates how many primes to
# compute (default: 10)
if (params[:count] != nil) then
count = params[:count].to_i()
else
count = 10
end
# Fill in @primes array with prime numbers
@primes = []
candidate = 2
while (@primes.length < count)
isPrime = true
# If any of the known primes divides into the candidate
# evenly, then the candidate isn't prime.
@primes.each do |prime|
if ((candidate % prime) == 0) then
isPrime = false
break
end
end
if (isPrime) then
@primes << candidate
end
candidate += 1
end
end
end
- Corresponding view:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><%= @primes.length %> Prime Numbers</title>
<%= stylesheet_link_tag 'main' %>
</head>
<body>
<p>
The first <%= @primes.length %> prime numbers are:
</p>
<table class="oddEven" cellspacing="0">
<tr class="header"><td>Prime Numbers</td></tr>
<% @primes.each do |prime| %>
<tr class="<%= cycle('odd', 'even') %>">
<td><%= prime %></td>
</tr>
<% end %>
</table>
</body>
</html>
Directory Structure
- Rails assumes a particular file structure for applications.
Some example directories (see book for more information):
app/controllers
: Ruby files containing controller
classes
app/models
: model definitions
app/views/
controller: template files
for the controller named controller
db/migrate
: database migration files
public
: static files accessible via URLs
public/images/
iii: image file
accessible at the URL /images/
iii
public/javascripts/
jjj: Javascript file
accessible at the URL /javascripts/
jjj
public/stylesheets/
sss: CSS file
accessible at the URL /stylesheets/
sss
Layouts
- Layout: standard frame used for one or more pages
- DOCTYPE and other boilerplate
- Header, footer, sidebar, etc.
yield
marks where the main template should
be inserted.
- The regular template is expanded before the layout
is invoked so it can set variables that personalize the layout
for individual pages (e.g., title)
- Files for layouts:
app/views/layouts/xyz.html.erb
: default
layout for all URLs in XyzController.
app/views/layouts/application.html.erb
: default
layout for all URLs in the application.
Partial-Page Templates
- Basic idea: encapsulate the rendering of common elements in
a reasonable way.
- Looks like any other template.
- Invoked with the
render
method:
<%= render(:partial => "foo") %>
Will render the template _foo.html.erb
in the
same directory as the calling template.
- Can pass arguments to the rendered template (see book for
details).