Ruby on Rails 3 View

Rails View Rendering using Naming Convention

For URL & Rails route rule

http::/host_name/orders
 resources :orders

Rails controller

class OrdersController < ApplicationController
 def index
    @orders = Order.all
  end
end

By default, controllers automatically render views to the same name as the action: action.html.erb

 app/views/orders/index.html.erb
<table>
<% @orders.each do |order| %>
  <tr>
    <td><%= order.title %></td>
    <td><%= link_to 'Show', order %></td>
    <td><%= link_to 'Edit', edit_order_path(order) %></td>
    <td><%= link_to 'Remove', order, :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>
</table>

<%= link_to 'New Order', new_order_path %>

Rails View Rendering using "render" (Override the default)

Do not render anything

render :nothing => true

Use the rendering file of action "something": something.html.erb

render "something"

render :something               # Same as above

render :action => "something"   # Same as above

All of the above (render :action => "something") will NOT call the action. Only invoke the view

Use the rendering file of another controller

render 'billings/show'

Use the rendering file of another Rails application

render "/home/user1/my_sys/my_app/app/views/services/show"

# Render with the current layout
render "/home/user1/my_sys/my_app/app/views/services/show" :layout => true
  • For file rendering, :layout is default to false

Inline rendering without a view

render :inline =>
  "<% orders.each do |p| %><p><%= p.title %><p><% end %>"

Use JavaScript to change the client HTML

render :update do |page|
  page.replace_html 'some_label', "My Text"
end

Rendering to a String

Output it as a String instead of a HTTP response

html_text = render_to_string

html_text = render_to_string :some_action_name

Rendering Ajax, JSON, XML

Return a string in particular for Ajax calls

render :text => "correct"

Set :layout => true to render the text with the current layout file

Render @account Rails model in JSON format

# Rails call @account.to_json for the JSON data
render :json => @account

Rendering @account Rails model for XML

# Rails call @account.to_xml for the JSON data
render :xml => @account

Render output as JavaScript

render :js => "alert('Warning.');"

Support multiple output format (HTML or XML)

class AccountsController < ApplicationController
  def index
    @accounts = Account.all
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @accounts}
    end
  end
end

Rails render option

render :file => filename, :content_type => 'application/rss'

Options for render (E.g. render :text => "data", :layout => true)

Option for "render" Description
:layout => true Use current layout to render the data
:layout => 'my_layout' Use a different layout file
:content_type => 'text/html' Define content type
:status => 500 HTTP Response code: render :status => 500
:status => :forbidden HTTP Response code using symbol
:location Set the HTTP location header :location => user_url(@user)

Invoke more than 1 render in a controller will result in an exception. But if no rendering has been done before the method return, Rails will invoke the default action view

Rails View Rendering using "redirect_to" Method

"redirect_to" send a redirect request to the browser to a different URL. (HTTP 302 temporary move response)

# Redirect to view the @account detail
redirect_to @account

# Redirect to /accounts (Inside the controller "accounts")
redirect_to accounts_path

# Redirect to /home/index (Inside the controller "home")
redirect_to :action => "index"

# Redirect with a specific HTTP status
redirect_to accounts_path, :status => 301

# Redirect to home page
redirect_to root_url

redirect_to :back  # Back to last page visited based on the value in HTTP_REFERER
  • redirect_to can take arguments similar to those in link_to or url_for

Rails Response Rendering using "head" Method

Responding with a HTTP header only

head :bad_request

Add a location attribute to the HTTP response

head :created, :location => order_path(@order)

Layout

If Layout is used, Rails first renders the layout which later "yield" to the view

Edit the layout for Controller "Home"

app/views/layouts/home.html.erb
<html>
<head>
...
<body>

<!-- Invoke the view file -->
<%= yield %>
</body>

If the controller's layout file is missing, Rails will use the application wide layout

/app/views/layouts/application.html.erb

Use Non-default Layout

class HomeController < ApplicationController
  # Define a new name for the layout file
  layout "my_layout"

  def index
     @message = "hello"
  end
end

The new layout file is locate at

app/views/layouts/my_layout.html.erb

Apply the layout on/except the following methods of the controller

layout "my_layout", :only => [:edit, :show]

layout "my_layout", :except => [:edit, :show]

Define an application wide layout

class ApplicationController < ActionController::Base
  layout "top_layout"
  ...
end

Layout with the most limited scope takes higher precedence over other

Determine Layout File Programmatic

class HomeController < ApplicationController
  # Layout file name determine by a method call
  layout :choose_layout

  def choose_layout
    # Add programming logic to determine which layout to use
    "my_layout"
  end
end

Pass in a Proc in determine the layout

layout Proc.new { |controller| controller.request.xhr? ? 'layout1' : 'layout2' }

Multiple Yield Regions in Rails

Include sub-regions in the layout

Layout
<html>
<body>

<!-- Invoke the view file -->
<%= yield %>

<!-- Also include sub_content_section from the view file -->
<%= yield :sub_content_section %>
</body>

Define sub-regions in a view

View
<h1> Welcome: Home Page </h1>

<p><%= @message %></p>

<!-- Content for sub_content_section -->
<% content_for(:sub_content_section) do %>
  <p> Additional content </p>
<% end %>
  • <%= yield %> will include
    <h1> Welcome: Home Page </h1>
    
    <p><%= @message %></p>
    
  • <%= yield :sub_content_section %> will include
    <% content_for(:sub_content_section) do %>
      <p> Additional content </p>
    <% end %>
    

Using Partials

Partial eliminates duplication by allowing views to shared common partials for view rendering

Convert

app/views/accounts/show.html.erb
...
<%= link_to 'Edit', edit_account_path(@account) %> |
<%= link_to 'Back', accounts_path %>

To

...
<%= render "footer" %>
  • Use _footer.html.erb to render the partials
...
<%= render "common/footer" %>
  • Use app/views/common/_footer.html.erb to render the partials

Create the partial view _footer.html.erb

An underscore before the filename is required to indicate the view is a partial view

app/views/accounts/_footer.html.erb
<%= link_to 'Edit', edit_account_path(@account) %> |
<%= link_to 'Back', accounts_path %>

Use a layout to render the partial view

<%= render "footer", :layout => "footer_layout" %>

Using variables in partial view

Passing variables

View
<%= render :partial => "footer", :locals =>
  {:att1 => @value1, :att2 => @value2, :acc =>@account }

Accessing variables

Partial View
<%= acc.user_name *>

User :object to pass @my_order to the partial with the same name as the partial (order)

<%= render :partial => "order", :object => @my_order %>
<%= order.order_name %>

Pass an object "@order" to the partials _order with a local variable name "order"

<%= render @order %>

Rendering Collection Objects in Partials

Rendering collection

View
<h1>Items</h1>
<%= render :partial => @items %>

Or

<%= render @items %>
  • render invoke the partial view _item for each item in the collection @items
  • each is accessible with the name item
_item.html.erb
<p>Item Name: <%= item.item_name %></p>
Current count: <%= item_counter %>
  • _count contains the current count of the collection being rendered

render use the name of the class to determine the partial view name

<%= render [order1, order2, special1] %>
  • order1, order2 will use the partial view _order
  • special1 will use the partials view _special

Use :as to override the local variable name used in the partial

<%= render :partial => "order", :collection => @orders, :as => :my_order %>
my_order.order_name

Passing local variables

<%= render :partial => 'order', :collection => @orders,
           :as => :my_order, :locals => {:price => 10} %>

To use a spacer between the rendering of a collection

<%= render @orders, :spacer_template => "order_spacer" %>
  • Rails will render the _order_spacer partial between each collection.

JavaScript in Rails

To include JavaScript (public/javascripts/business.js and public/common/standard.js)

<%= javascript_include_tag "business", "/common/standard" %>

To make it available to the whole application, put it in the application layout file

Include external JavaScript in Rails

<%= javascript_include_tag "http://opensource.com/jquery.js" %>

Load the Prototype and Scriptaculous libraries also

<%= javascript_include_tag :defaults %>

Load all JavaScript under public/javascripts and those out of the box JavaScripts inside it

<%= javascript_include_tag :all %>

Same us above plus all JavaScripts in the sub-directories

<%= javascript_include_tag :all, :recursive => true %>

For production, enabled the cache so the JavaScripts are send in one single file

<%= javascript_include_tag "business", "/common/standard" :cache => true %>

CSS Style Sheet in Rails

To include CSS files (public/stylesheets/main.css and public/common/style.css)

<%=  stylesheet_link_tag "main", "/common/style" %>

To make it available to the whole application, put it in the application layout file

Include external CSS in Rails

<%= stylesheet_link_tag "http://opensource.com/common.css" %>

Load all CSS under public/stylesheets

<%= stylesheet_link_tag :all %>

Same us above plus all files in all sub-directories

<%= stylesheet_link_tag :all, :recursive => true %>

For production, enabled the cache so the JavaScripts are send in one single file

<%=  stylesheet_link_tag "main", "/common/style" :cache => true %>

Escape HTML data

By default, all data is HTML escaped in a view, to avoid it

<%= raw account.comment %>
<%= raw "<b>Will not work without the raw method</b> %>

Do not use "raw" unless the data is sanitized or safe

Rails Image

<%= image_tag "logo.png" %>

<%= image_tag "icons/footer.gif", {:height => 50} %>

<%= image_tag "logo.png", :alt => "Home",
                          :id => "LogoImage",
                          :size => "30x30" %>

  • Default path for files are public/images

Other Rails Media Tag

<%= video_tag "promote.ogg" %>
<%= audio_tag "promote.mp3" %>

Suppress Extra Space

To suppress extra new lines in html code, use "-%>" to close the ruby code

<% for i in 1..@count -%>
  <p><%= @message -%></p>
<% end -%>

It removes the extra newlines in the HTML code. It has no impact on how HTML is rendered