Action View Basics

Introduction

Where Templates Live

Template Environment

Three Common Template Types

Serving Different Content Types


# The respond_to method will use the HTTP Accept header or any extension in the URL.
# So if the URL is /people/1.xml you will get XML back.

# GET /posts/1
# GET /posts/1.xml
def show
  @post = Post.find(params[:id])
  respond_to do |format|
    format.html # show.html.erb
    format.xml  { render :xml => @post }
  end
end

Builder Template Example: RSS


xml.instruct!
xml.rss "version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/" do
  xml.channel do
    xml.title "Recent comments for #{@user.login}" 
    xml.link @rss_url
    xml.pubDate CGI.rfc1123_date(@comments.first ? @comments.first.updated_at : Time.now)
    xml.description "" 
    @comments.each do |comment|
      xml.item do
        xml.title "Comment by #{comment.creation_user.login} #{time_ago_in_words comment.created_at} ago" 
        xml.link @server_url + comment_url(comment)
        xml.description h(comment.body)
        xml.pubDate CGI.rfc1123_date(comment.updated_at)
        xml.guid @server_url + comment_url(comment)
        xml.author h(comment.creation_user.login)
      end
    end
  end
end

Generating Atom Feeds


# app/views/posts/index.atom.builder:
atom_feed do |feed|
   feed.title("My great blog!")
   feed.updated((@posts.first.created_at))
   for post in @posts
     feed.entry(post) do |entry|
       entry.title(post.title)
       entry.content(post.body, :type => 'html')
       entry.author do |author|
         author.name("DHH")
       end
      end
   end
end

.html.erb Templates


# Evaluate Ruby code and print the last evaluated value to the page.
<%= ruby code here %> 

#  Evaluates Ruby code without outputting anything to the page
<% ruby code here %>

# Use a minus sign to avoid printing a newline to the page
<%= ... %->
<% ... %->

# HTML quoting/escaping with the h() helper method
<%=h comment.header %>

Partials

Rendering Partials


# Inside a controller action
render :partial => 'name_of_partial'

# In an .html.erb template
<%= render :partial => 'name_of_partial' %>

Passing Variables to Partials


# Controller instance variables are available
<%=h @article.name @%

# You can pass any objects into local variables in the partial:
# render :partial => 'article', :locals => { :article => @article, :options => @options }
<%=h article.name %>

# The :object argument initializes local variable with same name as partial.
# render :partial => 'article', :object => @an_article
<%= article.name %

Partials and Collections


<% for article in @articles %>
  <%= render :partial => 'article', :object => article %>
<% end %>

# Can be written more concisely with the :collection argument:
<%= render :partial => 'article', :collection => @articles %>

Layouts

Determining whith Layout to Use


# 1. Layout specified when you invoke render
render 'some_template', :layout => 'my_special_layout'
render 'some_template', :layout => false # no layout

# 2. Layout specified for the controller
layout 'standard', :except => [:rss, :atom]
layout nil # turns off layouts

# 3. Rails looks for a controller layout at:
app/views/layouts/controller_name.html.erb

# 4. Rails looks for an application layout in the file:
app/views/layouts/application.html.erb

Dynamic Layout Selection


class BlogController < ActionController::Base
  layout :determine_layout

  private
  def determine_layout
    user.admin? ? "admin" : "standard" 
  end
end

Partial Layouts


# in posts/_boxed.html.erb
<div class='box'>
  <div id='post_header_<%= post.id %>'><%= yield %></div>
</div>

# in posts/show.html.erb
<% render(:layout => 'boxed', :locals => {:post => @post}) do %>
  <%= post.title %> published on <%= post.published_at %>
<% end %>

Passing Data to Layouts


# You can pass data to layouts with instance variables
<%=h @page_title %>

# You can pass parts of your template with content_for.
# In your template:
<% content_for(:left_menu) %>
  ...
<% end %>
# In your layout:
<% yield :left_menu %>

Helpers

text_helper.rb


truncate("Once upon a time in a world far far away", 14)
highlight('You searched for: rails', 'rails')
excerpt('This is an example', 'an', 5)
pluralize(2, 'person')
word_wrap('Once upon a time', 4)
textilize(text)
markdown(text)
simple_format(text)
auto_link(text)
strip_links(text)
sanitize(html)
strip_tags(html)
<tr class="<%= cycle("even", "odd") -%>">

url_helper.rb


url_for({:controller => 'blog'}, :only_path => false)
link_to "Other Site", "http://www.rubyonrails.org/", :confirm => "Sure?" 
link_to "Image", { :action => "view" }, :popup => ['new_window','height=300,width=600']
link_to "Delete Image", { :action => "delete", :id => @image.id }, :method => :delete
<% link_to("Image", {:action => "view"}) do %><%= image_tag("/icons/icon.gif") %><% end %>
button_to "New", :action => "new" 
link_to_unless_current("Home", { :action => "index" })
mail_to "me@domain.com", "My email", :encode => "javascript" 
# => <script type="text/javascript">eval(unescape('%64%6f%63...%6d%65%6e'))</script>
mail_to "me@domain.com", "My email", :encode => "hex" 
# => <a href="mailto:%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">My email</a>

Stylesheets and JavaScript


# In app/views/layouts/application.html.erb
<html>
  <head>
    # Includes all stylesheets and javascripts and merges them into
    # a single file in production for better performance
    <%= stylesheet_link_tag :all, :cache => true %>
    <%= javascript_link_tag :all, :cache => true %>
  </head>
  ...

HAML – An Alternative Templating System


<div id='content'>
    <div class='left column'>
      <h2>Welcome to our site!</h2>
      <p>
        <%= print_information %>
      </p>
    </div>
    <div class="right column">
      <%= render :partial => "sidebar" %>
    </div>
</div>
=>

#content
    .left.column
      %h2 Welcome to our site!
      %p= print_information
    .right.column= render :partial => "sidebar"