Rails Introduction: Templates and Controllers
Lecture Notes for CS 142
Winter 2014
John Ousterhout
- Additional reading for this topic:
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 (Views)
- 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 is expanded by executing code snippets,
substituting the results into the document.
- 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
- Benefits of templates:
- Easy to visualize HTML structure
- Easy to see how dynamic data fits in
- 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>
- Query values available through params.
- Rails automatically escapes anything substituted with <%= ... %>
- Use html_safe to indicate that a value should not
be escaped
Controllers
- Most code should be in controller, not template; all template
does is substitute values into HTML. Controller also interfaces
with models, which manage application data.
- Lifecycle of an HTTP request:
- Routing (what method should handle an incoming request?):
- Rails receives incoming request
- Rails invokes a method in a Controller class, based on the
URL:
- Rails provides a general-purpose mechanism called routing
for this.
- Simple approach for this class: URL /rails_intro/hello is
routed to method
hello in class RailsIntroController. The controller
should be defined in the file
app/controllers/rails_intro_controller.rb
- 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 show_primes
# 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
is_prime = 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
is_prime = false
break
end
end
if is_prime 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:
app/controllers
: Ruby files containing controller
classes
app/views/
controller: template files
for the controller named controller
app/models
: model definitions
app/assets/images/
photo.jpg: image
corresponding to
<%= image_tag "photo.jpg" %>
app/assets/javascripts/
my_code.js: Javascript file
corresponding to
<%= javascript_include_tag "my_code" %>
app/assets/stylesheets/
my_styles.css: CSS file
corresponding to
<%= stylesheet_link_tag "my_styles" %>
db/migrate
: database migration files
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/application.html.erb
: default
layout for all URLs in the application.
app/views/layouts/xyz.html.erb
: default
layout for all URLs in XyzController.
Partial-Page Templates
- Encapsulate the rendering of common elements in a reusable way.
- Similar structure to other templates.
- 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.
<%= render(:partial => "shared/foo",
:locals => {:x => 24, :y =>36}) %>
- Template is in app/views/shared/_foo.html.erb
- The template will have local variables x and y.
Helper Functions
- Rails provides a collection of "helper" functions that are often
useful in templates:
- link_to: convenient for generating links:
<%= link_to(@name, {:action => :user_info, :id => @user_id}) %>
- Including images, stylesheets, or Javascript (files must be in
app/assets/images, app/assets/stylesheets,
or app/assets/javascripts):
<%= image_tag "icon.jpg" %>
<%= stylesheet_link_tag "main" %>
<%= javascript_include_tag "file1", "file2" %>