layouts and rendering in rails, season 2

69
Layouts and Rendering Ror lab. season 2 - the 12th round - December 15th, 2012 Hyoseong Choi

Upload: ror-lab

Post on 19-Jan-2015

3.366 views

Category:

Education


2 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Layouts and Rendering in Rails, Season 2

Layouts and Rendering

Ror lab. season 2- the 12th round -

December 15th, 2012

Hyoseong Choi

Page 2: Layouts and Rendering in Rails, Season 2

Contents

• Rendering methods

• Layouts with multiple content sections

• DRY using partial templates

• Nested layouts( or sub-templates)

Page 3: Layouts and Rendering in Rails, Season 2

Fit Together

Controller

Model View

Request

Response

heavy codes

DB

router

renderin

g

layout partial

Page 4: Layouts and Rendering in Rails, Season 2

Creating Response

• Three HTTP responses by Controller

➡ call “render” : full response

➡ call “redirect_to” : redirect status code

➡ call “head” : HTTP headers

Page 5: Layouts and Rendering in Rails, Season 2

Default Rendering

• views with names corresponding to valid routes.

• {action_name}.html.erb

Controllers automatically render

Page 6: Layouts and Rendering in Rails, Season 2

Default Rendering

class BooksController < ApplicationControllerend

BooksController

resources :booksconfig/routes.rb

<h1>Books are coming soon!</h1>app/views/books/index.html.erb

/books

Page 7: Layouts and Rendering in Rails, Season 2

Default Rendering

resources :booksconfig/routes.rb

$ rake routes CONTROLLER=books

books GET /books(.:format) books#index POST /books(.:format) books#create new_book GET /books/new(.:format) books#newedit_book GET /books/:id/edit(.:format) books#edit book GET /books/:id(.:format) books#show PUT /books/:id(.:format) books#update DELETE /books/:id(.:format) books#destroy

Page 8: Layouts and Rendering in Rails, Season 2

Default Rendering

class BooksController < ApplicationController  def index    @books = Book.all  endend

• {action_name}.html.erb: app/views/books/index.html.erbCoC

Page 9: Layouts and Rendering in Rails, Season 2

Default Rendering

<h1>Listing Books</h1> <table>  <tr>    <th>Title</th>    <th>Summary</th>    <th></th>    <th></th>    <th></th>  </tr> <% @books.each do |book| %>  <tr>    <td><%= book.title %></td>    <td><%= book.content %></td>    <td><%= link_to 'Show', book %></td>    <td><%= link_to 'Edit', edit_book_path(book) %></td>    <td><%= link_to 'Remove', book, :confirm => 'Are you sure?', :method => :delete %></td>  </tr><% end %></table> <br /> <%= link_to 'New book', new_book_path %

• app/views/books/index.html.erb

Page 10: Layouts and Rendering in Rails, Season 2

Using ‘Render’

class BooksController < ApplicationController  def index    @books = Book.all render “index” render_to_string “index” render :nothing => true  endend

Many ways to customize rendering•Default view : for a Rails template / a specific template / a file / inline code / nothing•text / JSON / XML

Page 11: Layouts and Rendering in Rails, Season 2

Using ‘Render’

def update  @book = Book.find(params[:id])  if @book.update_attributes(params[:book])    redirect_to(@book)  else    render "edit"  endend

Rendering an Action’s view

as a String

Page 12: Layouts and Rendering in Rails, Season 2

Using ‘Render’

def update  @book = Book.find(params[:id])  if @book.update_attributes(params[:book])    redirect_to(@book)  else    render :edit  endend

Rendering an Action’s view

as a Symbol

Page 13: Layouts and Rendering in Rails, Season 2

Using ‘Render’

def update  @book = Book.find(params[:id])  if @book.update_attributes(params[:book])    redirect_to(@book)  else    render :action => "edit"  endend

Rendering an Action’s view

to render “edit” action’s view

Page 14: Layouts and Rendering in Rails, Season 2

Using ‘Render’

def update  @book = Book.find(params[:id])  if @book.update_attributes(params[:book])    redirect_to(@book)  else    render "products/show"    render :template => "products/show"  endend

Rendering an Action’s Templatefrom Another Controller

from another controller

Page 15: Layouts and Rendering in Rails, Season 2

Using ‘Render’

def update  @book = Book.find(params[:id])  if @book.update_attributes(params[:book])    redirect_to(@book)  else render "/u/apps/warehouse_app/current/app/views/products/show"    render :file => "/u/apps/warehouse_app/current/app/views/products/show", :layout => true  endend

Rendering an Arbitrary File

Page 16: Layouts and Rendering in Rails, Season 2

Using ‘Render’

render :editrender :action => :editrender 'edit'render 'edit.html.erb'render :action => 'edit'render :action => 'edit.html.erb'render 'books/edit'render 'books/edit.html.erb'render :template => 'books/edit'render :template => 'books/edit.html.erb'render '/path/to/rails/app/views/books/edit'render '/path/to/rails/app/views/books/edit.html.erb'render :file => '/path/to/rails/app/views/books/edit'render :file => '/path/to/rails/app/views/books/edit.html.erb'

Wrapping it up

Page 17: Layouts and Rendering in Rails, Season 2

Using ‘Render’

render :inline =>  "<% products.each do |p| %><p><%= p.name %></p><% end %>"

with :inline

render :inline =>  "xml.p {'Horrid coding practice!'}", :type => :builder

default type :ERB

Page 18: Layouts and Rendering in Rails, Season 2

Using ‘Render’

render :text => "OK", :layout => true

with :text

short response to AJAX or web service requests

Page 19: Layouts and Rendering in Rails, Season 2

Using ‘Render’

render :json => @product

with :json

built-in support for JSON

Page 20: Layouts and Rendering in Rails, Season 2

Using ‘Render’

render :xml => @product

with :xml

built-in support for XML

Page 21: Layouts and Rendering in Rails, Season 2

Using ‘Render’

render :js => "alert('Hello Rails');"

with :js

built-in support for XML

Page 22: Layouts and Rendering in Rails, Season 2

Options for Render

• :content_type

• :layout

• :status

• :location

Page 23: Layouts and Rendering in Rails, Season 2

Options for Render

:content_type option

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

:html - text/html:json - application/json:xml - application/xml

Default MIME type

Page 24: Layouts and Rendering in Rails, Season 2

Options for Render

:layout option

render :layout => 'special_layout'

to tell Rails to use a specific file as the layout for the current action

render :layout => false

Page 25: Layouts and Rendering in Rails, Season 2

Options for Render

:location option

render :xml => photo, :location => photo_url(photo)

to set the HTTP Location header

Page 26: Layouts and Rendering in Rails, Season 2

Options for Render

:status option

render :status => 500render :status => :forbidden

http://www.codyfauser.com/2008/7/4/rails-http-status-code-to-symbol-mapping

Page 27: Layouts and Rendering in Rails, Season 2

Status Code Status Message Symbol

406 Not Acceptable :not_acceptable

407 Proxy Authentication Required

:proxy_authentication_required

408 Request Timeout :request_timeout

409 Conflict :conflict

410 Gone :gone

411 Length Required :length_required

412 Precondition Failed :precondition_failed

413 Request Entity Too Large :request_entity_too_large

414 Request-URI Too Long :request_uri_too_long

415 Unsupported Media Type :unsupported_media_type

416 Requested Range Not Satisfiable

:requested_range_not_satisfiable

417 Expectation Failed :expectation_failed

422 Unprocessable Entity :unprocessable_entity

423 Locked :locked

424 Failed Dependency :failed_dependency

426 Upgrade Required :upgrade_required

   

5xx Server Error5xx Server Error5xx Server Error

500 Internal Server Error :internal_server_error

501 Not Implemented :not_implemented

502 Bad Gateway :bad_gateway

503 Service Unavailable :service_unavailable

504 Gateway Timeout :gateway_timeout

505 HTTP Version Not Supported

:http_version_not_supported

507 Insufficient Storage :insufficient_storage

510 Not Extended :not_extended

Status Code Status Message Symbol1xx Informational1xx Informational1xx Informational100 Continue :continue101 Switching Protocols :switching_protocols102 Processing :processing   2xx Success2xx Success2xx Success200 OK :ok201 Created :created202 Accepted :accepted203 Non-Authoritative

Information:non_authoritative_information204 No Content :no_content

205 Reset Content :reset_content206 Partial Content :partial_content207 Multi-Status :multi_status226 IM Used :im_used   3xx Redirection3xx Redirection3xx Redirection300 Multiple Choices :multiple_choices301 Moved Permanently :moved_permanently302 Found :found303 See Other :see_other304 Not Modified :not_modified305 Use Proxy :use_proxy307 Temporary Redirect :temporary_redirect4xx Client Error4xx Client Error4xx Client Error400 Bad Request :bad_request401 Unauthorized :unauthorized402 Payment Required :payment_required403 Forbidden :forbidden404 Not Found :not_found405 Method Not Allowed :method_not_allowed

Page 28: Layouts and Rendering in Rails, Season 2

Finding Layouts

• Rails first looks for a file in app/views/layouts with the same base name as the controller.

Current layout

Controller layout

Application layout

inheritance

Page 29: Layouts and Rendering in Rails, Season 2

Finding LayoutsSpecifying Layouts for Controllers

class ProductsController < ApplicationController  layout "inventory"  #...end

class ApplicationController < ActionController::Base  layout "main"  #...end

app/views/layouts/inventory.html.erb

app/views/layouts/main.html.erb

Page 30: Layouts and Rendering in Rails, Season 2

Finding LayoutsChoosing Layouts at Runtime

class ProductsController < ApplicationController  layout :products_layout   def show    @product = Product.find(params[:id])  end   private    def products_layout      @current_user.special? ? "special" : "products"    end end

Page 31: Layouts and Rendering in Rails, Season 2

Finding LayoutsChoosing Layouts at Runtime

class ProductsController < ApplicationController  layout Proc.new { |controller| controller.request.xhr? ? 'popup' : 'application' }end

using inline method!

Page 32: Layouts and Rendering in Rails, Season 2

Finding LayoutsConditional Layouts

class ProductsController < ApplicationController  layout "product", :only => [:index, :rss]end

class ProductsController < ApplicationController  layout "product", :except => [:index, :rss]end

Page 33: Layouts and Rendering in Rails, Season 2

Finding LayoutsLayout Inheritance (1) cascading downward

class ApplicationController < ActionController::Base  layout "main"end

‣ application_controller.rb

class PostsController < ApplicationControllerend

‣ posts_controller.rb

Page 34: Layouts and Rendering in Rails, Season 2

Finding LayoutsLayout Inheritance (2) cascading downward

class SpecialPostsController < PostsController  layout "special"end

‣ special_posts_controller.rb

Page 35: Layouts and Rendering in Rails, Season 2

Finding LayoutsLayout Inheritance (3)

cascading downward

class OldPostsController < SpecialPostsController  layout false   def show    @post = Post.find(params[:id])  end   def index    @old_posts = Post.older    render :layout => "old"  end  # ...end

‣ old_posts_controller.rb

Page 36: Layouts and Rendering in Rails, Season 2

Using Redirect_to

• redirect_to - tell the browser to send a new request for a different URL

• cf. render - a view template

redirect_to photos_urlredirect_to :back

Page 37: Layouts and Rendering in Rails, Season 2

Using Redirect_to

redirect_to photos_path, :status => 301

Different Redirect Status Codedefault st

atus : 302

Page 38: Layouts and Rendering in Rails, Season 2

Using Redirect_toRender vs Redirect_to

def index  @books = Book.allend def show  @book = Book.find_by_id(params[:id])  if @book.nil?    render :action => "index"  endend

def index  @books = Book.allend def show  @book = Book.find_by_id(params[:id])  if @book.nil?    redirect_to :action => :index  endend

a round trip to the browser

Page 39: Layouts and Rendering in Rails, Season 2

Using Redirect_toRender vs Redirect_to

one stop rendering

def index  @books = Book.allend def show  @book = Book.find_by_id(params[:id])  if @book.nil?    @books = Book.all    render "index", :alert => 'Your book was not found!'  endend

Page 40: Layouts and Rendering in Rails, Season 2

Head-Only Responses

• render :nothing

• a more obvious alternative

‘head’ method

Page 41: Layouts and Rendering in Rails, Season 2

Head-Only Responses

head :bad_request

HTTP/1.1 400 Bad RequestConnection: closeDate: Sun, 24 Jan 2010 12:15:53 GMTTransfer-Encoding: chunkedContent-Type: text/html; charset=utf-8X-Runtime: 0.013483Set-Cookie: _blog_session=...snip...; path=/; HttpOnlyCache-Control: no-cache

Page 42: Layouts and Rendering in Rails, Season 2

Head-Only Responses

HTTP/1.1 201 CreatedConnection: closeDate: Sun, 24 Jan 2010 12:16:44 GMTTransfer-Encoding: chunkedLocation: /photos/1Content-Type: text/html; charset=utf-8X-Runtime: 0.083496Set-Cookie: _blog_session=...snip...; path=/; HttpOnlyCache-Control: no-cache

head :created, :location => photo_path(@photo)

Page 43: Layouts and Rendering in Rails, Season 2

Structuring Layouts

• Asset tags ( for asset links )

• yield and content_for ( for layouts )

• Partials ( for refactoring )

Three tools for knitting fragmented outputs

Page 44: Layouts and Rendering in Rails, Season 2

Structuring Layouts

• auto_discovery_link_tag

• javascript_include_tag

• stylesheet_link_tag

• image_tag

• video_tag

• audio_tag

Asset Tag Helpers

in <head> section

in <body> section

Page 45: Layouts and Rendering in Rails, Season 2

Structuring LayoutsAsset Tag Helpers

auto_discovery_link_tag

<%= auto_discovery_link_tag(:rss, {:action => "feed"},  {:title => "RSS Feed"}) %>

RSS or ATOM feeds

Page 46: Layouts and Rendering in Rails, Season 2

Structuring LayoutsAsset Tag Helpers

javascript_include_tag

<%= javascript_include_tag "main" %>

<script src='/assets/main.js' type="text/javascript"></script>

• app/assets/javascripts• lib/assets/javascripts• vendor/assets/javascripts

Page 47: Layouts and Rendering in Rails, Season 2

javascript_include_tag

<%= javascript_include_tag "main", "columns" %>

<%= javascript_include_tag "main", "/photos/columns" %>

<%= javascript_include_tag "http://example.com/main.js" %>

<%= javascript_include_tag :defaults %>

<%= javascript_include_tag :all %>

without asset pipeline

without asset pipeline

Page 48: Layouts and Rendering in Rails, Season 2

Disable Asset Pipeline

• config/application.rb

# Enable the asset pipeline

config.assets.enabled = true

Page 49: Layouts and Rendering in Rails, Season 2

javascript_include_tag

<%= javascript_include_tag :defaults %>

<script src="/javascripts/jquery.js" type="text/javascript"></script><script src="/javascripts/jquery_ujs.js" type="text/javascript"></script>

without asset pipeline

public/javascripts

• app/assets• lib/assets• vendor/assets

• public/javascriptswith asset pipeline without asset pipeline

Page 50: Layouts and Rendering in Rails, Season 2

config.action_view.javascript_expansions[:defaults] = %w(foo.js bar.js)

javascript_include_tag :defaults

config.action_view.javascript_expansions[:projects] = %w(projects.js tickets.js)

:defaults expansion in config/application.rb

new defaults expansion in config/application.rb

public/javascripts/application.js with :default

Page 51: Layouts and Rendering in Rails, Season 2

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

javascript_include_tag :all

<%= javascript_include_tag "main", "columns", :cache => true %>

public/javascripts/*.*

combining multiple files into a single download

public/javascripts/all.js

<%= javascript_include_tag "main", "columns",

  :cache => 'cache/main/display' %

location of cache

Page 52: Layouts and Rendering in Rails, Season 2

<%= stylesheet_link_tag "main" %>

stylesheet_link_tag

assets/stylesheets/ with Asset Pipeline

<%= stylesheet_link_tag "main", "columns" %>

<%= stylesheet_link_tag "main", "/photos/columns" %>

<%= stylesheet_link_tag "http://example.com/main.css" %>

Page 53: Layouts and Rendering in Rails, Season 2

<%= stylesheet_link_tag :all %>

stylesheet_link_tag :all

public/stylesheets/ without Asset Pipeline

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

<%= stylesheet_link_tag "main", "columns", :cache => true %>

<%= stylesheet_link_tag "main", "columns",  :cache => 'cache/main/display' %>

Page 54: Layouts and Rendering in Rails, Season 2

image/video/audio

• public/images

• public/videos

• public/audios

• app/assets/

• lib/assets/

• vendor/assets/

images/videos/audios/

images/videos/audios/

images/videos/audios/

Asset pipeline +Asset pipeline -

Page 55: Layouts and Rendering in Rails, Season 2

Yield

• a section where content from the view should be inserted.

<html>  <head>  </head>  <body>  <%= yield %>  </body></html>

<html>  <head>  <%= yield :head %>  </head>  <body>  <%= yield %>  </body></html>

single yield multiple yields

named yield

content_for

Page 56: Layouts and Rendering in Rails, Season 2

content_for

<% content_for :head do %>

  <title>A simple page</title>

<% end %>

 

<p>Hello, Rails!</p>

<%= yield :head %>

<html>  <head>  <title>A simple page</title>  </head>  <body>  <p>Hello, Rails!</p>  </body></html>

<html>  <head>  <%= yield :head %>  </head>  <body>  <%= yield %>  </body></html>

Page 57: Layouts and Rendering in Rails, Season 2

Partial

• breaking the render process into more chunks

• moving the code chunk to its own file

• _partial.html.erb vs partial.html.erb

• to simplify views

• partial layout

Page 58: Layouts and Rendering in Rails, Season 2

Partial<%= render "menu" %>

<%= render "shared/menu" %>

<%= render "shared/ad_banner" %> <h1>Products</h1> <p>Here are a few of our fine products:</p>... <%= render "shared/footer" %>

<%= render :partial => "link_area", :layout => "graybar"

Page 59: Layouts and Rendering in Rails, Season 2

Local Variables<h1>New zone</h1><%= error_messages_for :zone %><%= render :partial => "form", :locals => { :zone => @zone } %>

<%= form_for(zone) do |f| %>  <p>    <b>Zone name</b><br />    <%= f.text_field :name %>  </p>  <p>    <%= f.submit %>  </p><% end %>

Page 60: Layouts and Rendering in Rails, Season 2

A Partial variable

• a local variable with the same name as the partial

• pass an object in to this local variable

<%= render :partial => "customer", :object => @new_customer %>

<%= render @customer %>

Page 61: Layouts and Rendering in Rails, Season 2

Rendering Collections

Rails determines the name of the partial to use by looking at the model name in the collection. In fact, you can even create a heterogeneous collection and render it this way

<h1>Products</h1><%= render :partial => "product", :collection => @products %>

index.html.erb

<p>Product Name: <%= product.name %></p>_product.html.erb

Page 62: Layouts and Rendering in Rails, Season 2

Rendering Collections

Rails determines the name of the partial to use by looking at the model name in the collection. In fact, you can even create a heterogeneous collection and render it this way

<h1>Products</h1><%= render(@products) || ‘there are no products available.’ %>

<p>Product Name: <%= product.name %></p>

index.html.erb

_product.html.erb

rails 3.0

Page 63: Layouts and Rendering in Rails, Season 2

Heterogenous Collections

<h1>Contacts</h1><%= render [customer1, employee1, customer2, employee2] %>

index.html.erb

<p>Customer: <%= customer.name %></p>

customers/_customer.html.erb

<p>Employee: <%= employee.name %></p>employees/_employee.html.erb

Page 64: Layouts and Rendering in Rails, Season 2

Local Variables

render :partial => "product", :collection => @products, :as => :item %>

<%= render :partial => 'products', :collection => @products,           :as => :item, :locals => {:title => "Products Page"} %>

Page 65: Layouts and Rendering in Rails, Season 2

Spacer Templates

<%= render :partial => @products, :spacer_template => "product_ruler" %>

Page 66: Layouts and Rendering in Rails, Season 2

Layouts

• Application Layout

• Controller Layout

• Action Layout

• Partial Layout

Page 67: Layouts and Rendering in Rails, Season 2

Layouts<html>

  <head>

  <%= yield :head %>

  </head>

  <body>

  <%= yield %>

  </body>

</html>

layout

yield placeholder

yield(:head) content_for :head

yield(:bar) content_for :bar

<% content_for :head do %>

  <title>A simple page</

title>

<% end %>

 

<p>Hello, Rails!</p>

view template

Page 68: Layouts and Rendering in Rails, Season 2

Nested Layouts

<% content_for :stylesheets do %>  #top_menu {display: none}

  #right_menu {float: right; background-color:

yellow; color: black}

<% end %>

<% content_for :content do %>

  <div id="right_menu">Right menu items here</

div>

  <%= content_for?(:news_content)

? yield(:news_content) : yield %>

<% end %>

<%= render :template => 'layouts/application' %>

ApplicationController LayoutNewsController Layout

<html><head>

  <title><%= @page_title or 'Page Title' %></

title>

  <%= stylesheet_link_tag 'layout' %>

  <style type="text/css"> <%= yield :stylesheets %>

</style>

</head>

<body>

  <div id="top_menu">Top menu items here</div>  <div id="menu">Menu items here</div>

  <div id="content">

<%= content_for?(:content)

? yield(:content)

: yield %></div>

</body>

</html>

Page 69: Layouts and Rendering in Rails, Season 2

ROR Lab.

감사합니다.����������� ������������������