Ror lab. season 2
      - the 12th round -




Layouts and Rendering

      December 15th, 2012

        Hyoseong Choi
Contents

• Rendering methods
• Layouts with multiple content sections
• DRY using partial templates
• Nested layouts( or sub-templates)
Fit Together
                                               Request




                                        ro
                                          ut
                                              er
     hea
                     Controller
        vy                                ng
             cod                     deri
                es                ren
                                         layout     partial


             Model           View

DB                                                 Response
Creating Response

• Three HTTP responses by Controller
 ➡ call “render” : full response
 ➡ call “redirect_to” : redirect status code
 ➡ call “head” : HTTP headers
Default Rendering
Controllers automatically render

  • views with names corresponding to valid
     routes.
  • {action_name}.html.erb
Default Rendering
                    /books

 class BooksController < ApplicationController
 end
                                                  BooksController



 resources :books
                                                  config/routes.rb



 <h1>Books are coming soon!</h1>
                                   app/views/books/index.html.erb
Default Rendering
      resources :books
                                               config/routes.rb


$ rake routes CONTROLLER=books

    books GET      /books(.:format)            books#index
          POST     /books(.:format)            books#create
 new_book GET      /books/new(.:format)        books#new
edit_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
Default Rendering
   class BooksController < ApplicationController
     def index
       @books = Book.all
     end
   end




       • {action_name}.html.erb
C oC      : app/views/books/index.html.erb
Default Rendering
 • app/views/books/index.html.erb
    <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 %
Using ‘Render’
Many ways to customize rendering
• Default view
  : for a Rails template / a specific template / a file / inline code /
  nothing
• text / JSON / XML

 class BooksController < ApplicationController
   def index
     @books = Book.all
     render “index”
     render_to_string “index”
     render :nothing => true
   end
 end
Using ‘Render’
     Rendering an Action’s view


def update
  @book = Book.find(params[:id])
  if @book.update_attributes(params[:book])
    redirect_to(@book)
  else
    render "edit"
  end
           as a String
end
Using ‘Render’
     Rendering an Action’s view


def update
  @book = Book.find(params[:id])
  if @book.update_attributes(params[:book])
    redirect_to(@book)
  else
    render :edit
  end
           as a Symbol
end
Using ‘Render’
     Rendering an Action’s view


def update
  @book = Book.find(params[:id])
  if @book.update_attributes(params[:book])
    redirect_to(@book)
  else
    render :action => "edit"
  end
           to render “edit” action’s view
end
Using ‘Render’
 Rendering an Action’s Template
    from Another Controller

def update
  @book = Book.find(params[:id])
  if @book.update_attributes(params[:book])
    redirect_to(@book)
  else
    render "products/show"
    render :template => "products/show"
  end
            from another controller
end
Using ‘Render’
    Rendering an Arbitrary File

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
  end
end
Using ‘Render’
                Wrapping it up

render :edit
render :action => :edit
render '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'
Using ‘Render’
                   with :inline
                                              default type :ERB



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




render :inline =>
  "xml.p {'Horrid coding practice!'}", :type => :builder
Using ‘Render’
                    with :text

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




            short response to AJAX
            or web service requests
Using ‘Render’
                    with :json

render :json => @product




           built-in support for JSON
Using ‘Render’
                     with :xml

render :xml => @product




            built-in support for XML
Using ‘Render’
                      with :js

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




            built-in support for XML
Options
        for Render
• :content_type
• :layout
• :status
• :location
Options
            for Render
                :content_type option

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



                                 Default MIME type
      :html - text/html
      :json - application/json
      :xml - application/xml
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
Options
            for Render
                   :location option

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



                            to set the HTTP Location header
Options
               for Render
                           :status option

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




  http://www.codyfauser.com/2008/7/4/rails-http-status-code-to-symbol-mapping
Status Code        Status Message        Symbol                      Status Code        Status Message           Symbol
1xx Informational                                                    406                Not Acceptable           :not_acceptable
100                Continue              :continue                                      Proxy Authentication     :proxy_authentication_req
                                                                     407
101                Switching Protocols   :switching_protocols                           Required                 uired
                                                                     408                Request Timeout          :request_timeout
102                Processing            :processing
                                                                     409                Conflict                  :conflict
2xx Success                                                          410                Gone                     :gone
200                OK                    :ok                         411                Length Required          :length_required
201                Created               :created
                                                                     412                Precondition Failed      :precondition_failed
202                Accepted              :accepted
                                                                     413                Request Entity Too Large :request_entity_too_large
203                Non-Authoritative     :non_authoritative_inform
                   Information           ation                       414                Request-URI Too Long     :request_uri_too_long
204                No Content            :no_content
205                Reset Content         :reset_content              415                Unsupported Media Type :unsupported_media_type
206                Partial Content       :partial_content            416                Requested Range Not      :requested_range_not_sati
207                Multi-Status          :multi_status                                  Satisfiable               sfiable
                                                                     417                Expectation Failed       :expectation_failed
226                IM Used               :im_used
                                                                     422                Unprocessable Entity     :unprocessable_entity
 
                                                                     423                Locked                   :locked
3xx Redirection
300                Multiple Choices      :multiple_choices           424                Failed Dependency        :failed_dependency
301                Moved Permanently     :moved_permanently          426                Upgrade Required         :upgrade_required
302                Found                 :found                       
303                See Other             :see_other
                                                                     5xx Server Error
304                Not Modified           :not_modified
                                                                     500                Internal Server Error    :internal_server_error
305                Use Proxy             :use_proxy
307                Temporary Redirect    :temporary_redirect         501                Not Implemented          :not_implemented
4xx Client Error                                                     502                Bad Gateway              :bad_gateway
400                Bad Request           :bad_request                503                Service Unavailable      :service_unavailable
401                Unauthorized          :unauthorized
                                                                     504                Gateway Timeout          :gateway_timeout
402                Payment Required      :payment_required
                                                                     505                HTTP Version Not         :http_version_not_support
403                Forbidden             :forbidden                                     Supported                ed
404                Not Found             :not_found                  507                Insufficient Storage     :insufficient_storage

405                Method Not Allowed    :method_not_allowed         510                Not Extended             :not_extended
Finding Layouts
•   Rails first looks for a file in app/views/layouts
    with the same base name as the controller.




           Current
                              Controller layout
            layout

                                          inheritance


                              Application layout
Finding Layouts
      Specifying Layouts for Controllers


class ProductsController < ApplicationController
  layout "inventory"
  #...
end
                                 app/views/layouts/inventory.html.erb




class ApplicationController < ActionController::Base
  layout "main"
  #...
end
                                     app/views/layouts/main.html.erb
Finding Layouts
          Choosing 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
Finding Layouts
          Choosing Layouts at Runtime

class ProductsController < ApplicationController
  layout Proc.new { |controller|
controller.request.xhr? ? 'popup' : 'application' }
end
               using inline method!
Finding Layouts
               Conditional Layouts

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




class ProductsController < ApplicationController
  layout "product", :except => [:index, :rss]
end
Finding Layouts
               Layout Inheritance (1)        cascading downward




‣ application_controller.rb
 class ApplicationController < ActionController::Base
   layout "main"
 end



‣ posts_controller.rb
 class PostsController < ApplicationController
 end
Finding Layouts
               Layout Inheritance (2)        cascading downward




‣ special_posts_controller.rb
 class SpecialPostsController < PostsController
   layout "special"
 end
Finding Layouts
                                             cascading downward

               Layout Inheritance (3)
‣ old_posts_controller.rb
 class OldPostsController < SpecialPostsController
   layout false
  
   def show
     @post = Post.find(params[:id])
   end
  
   def index
     @old_posts = Post.older
     render :layout => "old"
   end
   # ...
 end
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_url
redirect_to :back
Using Redirect_to                                         s : 30
                                                                   2
                                                      tatu
                                                  lt s
                                          de   fau

       Different Redirect Status Code


redirect_to photos_path, :status => 301
Using Redirect_to
                       Render vs Redirect_to

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




                            a round trip to the browser
Using Redirect_to
             Render vs Redirect_to

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



                    one stop rendering
Head-Only
        Responses

• render :nothing
• a more obvious alternative
  ‘head’ method
Head-Only
          Responses
head :bad_request




HTTP/1.1 400 Bad Request
Connection: close
Date: Sun, 24 Jan 2010 12:15:53 GMT
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
X-Runtime: 0.013483
Set-Cookie: _blog_session=...snip...; path=/; HttpOnly
Cache-Control: no-cache
Head-Only
          Responses
head :created, :location => photo_path(@photo)




HTTP/1.1 201 Created
Connection: close
Date: Sun, 24 Jan 2010 12:16:44 GMT
Transfer-Encoding: chunked
Location: /photos/1
Content-Type: text/html; charset=utf-8
X-Runtime: 0.083496
Set-Cookie: _blog_session=...snip...; path=/; HttpOnly
Cache-Control: no-cache
Structuring
             Layouts
Three tools for knitting fragmented outputs

   • Asset tags ( for asset links )
   • yield and content_for ( for layouts )
   • Partials ( for refactoring )
Structuring
         Layouts
            Asset Tag Helpers

• auto_discovery_link_tag
• javascript_include_tag    in <head> section


• stylesheet_link_tag
• image_tag
• video_tag                 in <body> section


• audio_tag
Structuring
           Layouts
                Asset Tag Helpers

            auto_discovery_link_tag            RSS or ATOM feeds




<%= auto_discovery_link_tag(:rss, {:action => "feed"},
  {:title => "RSS Feed"}) %>
Structuring
             Layouts
                     Asset 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
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 %>    without asset pipeline




<%= javascript_include_tag :all %>   without asset pipeline
Disable
    Asset Pipeline

• config/application.rb
   # Enable the asset pipeline
    config.assets.enabled = true
javascript_include_tag



<%= javascript_include_tag :defaults %>             without asset pipeline




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


             public/javascripts


 with asset pipeline                   without asset pipeline
   • app/assets                         • public/javascripts
   • lib/assets
   • vendor/assets
javascript_include_tag :defaults


 :defaults expansion in config/application.rb


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




new defaults expansion in config/application.rb

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




public/javascripts/application.js with :default
javascript_include_tag :all


                          public/javascripts/*.*


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




combining multiple files into a single download

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

                                                public/javascripts/all.js


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


           location of cache
stylesheet_link_tag


 assets/stylesheets/ with Asset Pipeline


<%= stylesheet_link_tag "main" %>




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




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




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

 public/stylesheets/ without Asset Pipeline


<%= stylesheet_link_tag :all %>




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




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




<%= stylesheet_link_tag "main", "columns",
  :cache => 'cache/main/display' %>
image/video/audio
Asset pipeline -   Asset pipeline +

                   • app/assets/
                                     images/
                                     videos/


• public/images
                                     audios/




• public/videos    • lib/assets/
                                   images/
                                   videos/
                                   audios/


• public/audios
                   • vendor/assets/
                                             images/
                                             videos/
                                             audios/
Yield
    • a section where content from the view
        should be inserted.                                 content_for



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


            single yield                  multiple yields
content_for
                                            <html>
                                              <head>
                                              <%= yield :head %>
                                              </head>
                       <%= yield :head %>     <body>
                                              <%= yield %>
                                              </body>
<% content_for :head do %>                  </html>
  <title>A simple page</title>
<% end %>
                                            <html>
<p>Hello, Rails!</p>                          <head>
                                              <title>A simple page</title>
                                              </head>
                                              <body>
                                              <p>Hello, Rails!</p>
                                              </body>
                                            </html>
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
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"
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 %>
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 %>
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
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




                                                               ra
                                                                   ils
                                                              3.
  <h1>Products</h1>                                              0
  <%= render(@products) || ‘there are no products
  available.’ %>
                                                    index.html.erb



  <p>Product Name: <%= product.name %></p>
                                                _product.html.erb
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
Local Variables
render :partial => "product",
       :collection => @products,
       :as => :item %>




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

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

• Application Layout
• Controller Layout
• Action Layout
• Partial Layout
Layouts
            layout               view template
<html>                  <% content_for :head do %>
  <head>                  <title>A simple page</
  <%= yield :head %>    title>
  </head>               <% end %>
  <body>                 
  <%= yield %>          <p>Hello, Rails!</p>
  </body>
</html>
                               yield       placeholder



                            yield(:head)    content_for :head



                            yield(:bar)      content_for :bar
Nested Layouts
     NewsController Layout                           ApplicationController Layout
<% content_for :stylesheets do %>
                                                   <html>
  #top_menu {display: none}
                                                   <head>
  #right_menu {float: right; background-color:
                                                     <title><%= @page_title or 'Page Title' %></
yellow; color: black}
                                                   title>
<% end %>
                                                     <%= stylesheet_link_tag 'layout' %>
                                                     <style type="text/css">
<% content_for :content do %>
                                                       <%= yield :stylesheets %>
  <div id="right_menu">Right menu items here</
                                                     </style>
div>
                                                   </head>
  <%= content_for?(:news_content)
                                                   <body>
      ? yield(:news_content)
                                                     <div id="top_menu">Top menu items here</div>
      : yield %>
                                                     <div id="menu">Menu items here</div>
<% end %>
                                                     <div id="content">
                                                       <%= content_for?(:content)
                                                           ? yield(:content)
<%= render :template => 'layouts/application' %>
                                                           : yield %>
                                                   </div>
                                                   </body>
                                                   </html>
감사합니다.

Layouts and Rendering in Rails, Season 2

  • 1.
    Ror lab. season2 - the 12th round - Layouts and Rendering December 15th, 2012 Hyoseong Choi
  • 2.
    Contents • Rendering methods •Layouts with multiple content sections • DRY using partial templates • Nested layouts( or sub-templates)
  • 3.
    Fit Together Request ro ut er hea Controller vy ng cod deri es ren layout partial Model View DB Response
  • 4.
    Creating Response • ThreeHTTP responses by Controller ➡ call “render” : full response ➡ call “redirect_to” : redirect status code ➡ call “head” : HTTP headers
  • 5.
    Default Rendering Controllers automaticallyrender • views with names corresponding to valid routes. • {action_name}.html.erb
  • 6.
    Default Rendering /books class BooksController < ApplicationController end BooksController resources :books config/routes.rb <h1>Books are coming soon!</h1> app/views/books/index.html.erb
  • 7.
    Default Rendering resources :books config/routes.rb $ rake routes CONTROLLER=books books GET /books(.:format) books#index POST /books(.:format) books#create new_book GET /books/new(.:format) books#new edit_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
  • 8.
    Default Rendering class BooksController < ApplicationController   def index     @books = Book.all   end end • {action_name}.html.erb C oC : app/views/books/index.html.erb
  • 9.
    Default Rendering •app/views/books/index.html.erb <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 %
  • 10.
    Using ‘Render’ Many waysto customize rendering • Default view : for a Rails template / a specific template / a file / inline code / nothing • text / JSON / XML class BooksController < ApplicationController   def index     @books = Book.all render “index” render_to_string “index” render :nothing => true   end end
  • 11.
    Using ‘Render’ Rendering an Action’s view def update   @book = Book.find(params[:id])   if @book.update_attributes(params[:book])     redirect_to(@book)   else     render "edit"   end as a String end
  • 12.
    Using ‘Render’ Rendering an Action’s view def update   @book = Book.find(params[:id])   if @book.update_attributes(params[:book])     redirect_to(@book)   else     render :edit   end as a Symbol end
  • 13.
    Using ‘Render’ Rendering an Action’s view def update   @book = Book.find(params[:id])   if @book.update_attributes(params[:book])     redirect_to(@book)   else     render :action => "edit"   end to render “edit” action’s view end
  • 14.
    Using ‘Render’ Renderingan Action’s Template from Another Controller def update   @book = Book.find(params[:id])   if @book.update_attributes(params[:book])     redirect_to(@book)   else     render "products/show"     render :template => "products/show"   end from another controller end
  • 15.
    Using ‘Render’ Rendering an Arbitrary File 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   end end
  • 16.
    Using ‘Render’ Wrapping it up render :edit render :action => :edit render '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'
  • 17.
    Using ‘Render’ with :inline default type :ERB render :inline =>   "<% products.each do |p| %><p><%= p.name %></p><% end %>" render :inline =>   "xml.p {'Horrid coding practice!'}", :type => :builder
  • 18.
    Using ‘Render’ with :text render :text => "OK", :layout => true short response to AJAX or web service requests
  • 19.
    Using ‘Render’ with :json render :json => @product built-in support for JSON
  • 20.
    Using ‘Render’ with :xml render :xml => @product built-in support for XML
  • 21.
    Using ‘Render’ with :js render :js => "alert('Hello Rails');" built-in support for XML
  • 22.
    Options for Render • :content_type • :layout • :status • :location
  • 23.
    Options for Render :content_type option render :file => filename, :content_type => 'application/rss' Default MIME type :html - text/html :json - application/json :xml - application/xml
  • 24.
    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
  • 25.
    Options for Render :location option render :xml => photo, :location => photo_url(photo) to set the HTTP Location header
  • 26.
    Options for Render :status option render :status => 500 render :status => :forbidden http://www.codyfauser.com/2008/7/4/rails-http-status-code-to-symbol-mapping
  • 27.
    Status Code Status Message Symbol Status Code Status Message Symbol 1xx Informational 406 Not Acceptable :not_acceptable 100 Continue :continue Proxy Authentication :proxy_authentication_req 407 101 Switching Protocols :switching_protocols Required uired 408 Request Timeout :request_timeout 102 Processing :processing   409 Conflict :conflict 2xx Success 410 Gone :gone 200 OK :ok 411 Length Required :length_required 201 Created :created 412 Precondition Failed :precondition_failed 202 Accepted :accepted 413 Request Entity Too Large :request_entity_too_large 203 Non-Authoritative :non_authoritative_inform Information ation 414 Request-URI Too Long :request_uri_too_long 204 No Content :no_content 205 Reset Content :reset_content 415 Unsupported Media Type :unsupported_media_type 206 Partial Content :partial_content 416 Requested Range Not :requested_range_not_sati 207 Multi-Status :multi_status Satisfiable sfiable 417 Expectation Failed :expectation_failed 226 IM Used :im_used 422 Unprocessable Entity :unprocessable_entity   423 Locked :locked 3xx Redirection 300 Multiple Choices :multiple_choices 424 Failed Dependency :failed_dependency 301 Moved Permanently :moved_permanently 426 Upgrade Required :upgrade_required 302 Found :found   303 See Other :see_other 5xx Server Error 304 Not Modified :not_modified 500 Internal Server Error :internal_server_error 305 Use Proxy :use_proxy 307 Temporary Redirect :temporary_redirect 501 Not Implemented :not_implemented 4xx Client Error 502 Bad Gateway :bad_gateway 400 Bad Request :bad_request 503 Service Unavailable :service_unavailable 401 Unauthorized :unauthorized 504 Gateway Timeout :gateway_timeout 402 Payment Required :payment_required 505 HTTP Version Not :http_version_not_support 403 Forbidden :forbidden Supported ed 404 Not Found :not_found 507 Insufficient Storage :insufficient_storage 405 Method Not Allowed :method_not_allowed 510 Not Extended :not_extended
  • 28.
    Finding Layouts • Rails first looks for a file in app/views/layouts with the same base name as the controller. Current Controller layout layout inheritance Application layout
  • 29.
    Finding Layouts Specifying Layouts for Controllers class ProductsController < ApplicationController   layout "inventory"   #... end app/views/layouts/inventory.html.erb class ApplicationController < ActionController::Base   layout "main"   #... end app/views/layouts/main.html.erb
  • 30.
    Finding Layouts Choosing 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
  • 31.
    Finding Layouts Choosing Layouts at Runtime class ProductsController < ApplicationController   layout Proc.new { |controller| controller.request.xhr? ? 'popup' : 'application' } end using inline method!
  • 32.
    Finding Layouts Conditional Layouts class ProductsController < ApplicationController   layout "product", :only => [:index, :rss] end class ProductsController < ApplicationController   layout "product", :except => [:index, :rss] end
  • 33.
    Finding Layouts Layout Inheritance (1) cascading downward ‣ application_controller.rb class ApplicationController < ActionController::Base   layout "main" end ‣ posts_controller.rb class PostsController < ApplicationController end
  • 34.
    Finding Layouts Layout Inheritance (2) cascading downward ‣ special_posts_controller.rb class SpecialPostsController < PostsController   layout "special" end
  • 35.
    Finding Layouts cascading downward Layout Inheritance (3) ‣ old_posts_controller.rb class OldPostsController < SpecialPostsController   layout false     def show     @post = Post.find(params[:id])   end     def index     @old_posts = Post.older     render :layout => "old"   end   # ... end
  • 36.
    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_url redirect_to :back
  • 37.
    Using Redirect_to s : 30 2 tatu lt s de fau Different Redirect Status Code redirect_to photos_path, :status => 301
  • 38.
    Using Redirect_to Render vs Redirect_to def index def index   @books = Book.all   @books = Book.all end end     def show def show   @book = Book.find_by_id(params[:id])   @book = Book.find_by_id(params[:id])   if @book.nil?   if @book.nil?     render :action => "index"     redirect_to :action => :index   end   end end end a round trip to the browser
  • 39.
    Using Redirect_to Render vs Redirect_to def index   @books = Book.all end   def show   @book = Book.find_by_id(params[:id])   if @book.nil?     @books = Book.all     render "index", :alert => 'Your book was not found!'   end end one stop rendering
  • 40.
    Head-Only Responses • render :nothing • a more obvious alternative ‘head’ method
  • 41.
    Head-Only Responses head :bad_request HTTP/1.1 400 Bad Request Connection: close Date: Sun, 24 Jan 2010 12:15:53 GMT Transfer-Encoding: chunked Content-Type: text/html; charset=utf-8 X-Runtime: 0.013483 Set-Cookie: _blog_session=...snip...; path=/; HttpOnly Cache-Control: no-cache
  • 42.
    Head-Only Responses head :created, :location => photo_path(@photo) HTTP/1.1 201 Created Connection: close Date: Sun, 24 Jan 2010 12:16:44 GMT Transfer-Encoding: chunked Location: /photos/1 Content-Type: text/html; charset=utf-8 X-Runtime: 0.083496 Set-Cookie: _blog_session=...snip...; path=/; HttpOnly Cache-Control: no-cache
  • 43.
    Structuring Layouts Three tools for knitting fragmented outputs • Asset tags ( for asset links ) • yield and content_for ( for layouts ) • Partials ( for refactoring )
  • 44.
    Structuring Layouts Asset Tag Helpers • auto_discovery_link_tag • javascript_include_tag in <head> section • stylesheet_link_tag • image_tag • video_tag in <body> section • audio_tag
  • 45.
    Structuring Layouts Asset Tag Helpers auto_discovery_link_tag RSS or ATOM feeds <%= auto_discovery_link_tag(:rss, {:action => "feed"},   {:title => "RSS Feed"}) %>
  • 46.
    Structuring Layouts Asset 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
  • 47.
    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 %> without asset pipeline <%= javascript_include_tag :all %> without asset pipeline
  • 48.
    Disable Asset Pipeline • config/application.rb # Enable the asset pipeline config.assets.enabled = true
  • 49.
    javascript_include_tag <%= javascript_include_tag :defaults%> without asset pipeline <script src="/javascripts/jquery.js" type="text/javascript"></script> <script src="/javascripts/jquery_ujs.js" type="text/javascript"></script> public/javascripts with asset pipeline without asset pipeline • app/assets • public/javascripts • lib/assets • vendor/assets
  • 50.
    javascript_include_tag :defaults :defaultsexpansion in config/application.rb config.action_view.javascript_expansions[:defaults] = %w(foo.js bar.js) new defaults expansion in config/application.rb config.action_view.javascript_expansions[:projects] = %w(projects.js tickets.js) public/javascripts/application.js with :default
  • 51.
    javascript_include_tag :all public/javascripts/*.* <%= javascript_include_tag :all, :recursive => true %> combining multiple files into a single download <%= javascript_include_tag "main", "columns", :cache => true %> public/javascripts/all.js <%= javascript_include_tag "main", "columns",   :cache => 'cache/main/display' % location of cache
  • 52.
    stylesheet_link_tag assets/stylesheets/ withAsset Pipeline <%= stylesheet_link_tag "main" %> <%= stylesheet_link_tag "main", "columns" %> <%= stylesheet_link_tag "main", "/photos/columns" %> <%= stylesheet_link_tag "http://example.com/main.css" %>
  • 53.
    stylesheet_link_tag :all public/stylesheets/without Asset Pipeline <%= stylesheet_link_tag :all %> <%= stylesheet_link_tag :all, :recursive => true %> <%= stylesheet_link_tag "main", "columns", :cache => true %> <%= stylesheet_link_tag "main", "columns",   :cache => 'cache/main/display' %>
  • 54.
    image/video/audio Asset pipeline - Asset pipeline + • app/assets/ images/ videos/ • public/images audios/ • public/videos • lib/assets/ images/ videos/ audios/ • public/audios • vendor/assets/ images/ videos/ audios/
  • 55.
    Yield • a section where content from the view should be inserted. content_for <html> <html> named yield   <head>   <head>   </head>   <%= yield :head %>   <body>   </head>   <%= yield %>   <body>   </body>   <%= yield %> </html>   </body> </html> single yield multiple yields
  • 56.
    content_for <html>   <head>   <%= yield :head %>   </head> <%= yield :head %>   <body>   <%= yield %>   </body> <% content_for :head do %> </html>   <title>A simple page</title> <% end %>   <html> <p>Hello, Rails!</p>   <head>   <title>A simple page</title>   </head>   <body>   <p>Hello, Rails!</p>   </body> </html>
  • 57.
    Partial • breaking therender process into more chunks • moving the code chunk to its own file • _partial.html.erb vs partial.html.erb • to simplify views • partial layout
  • 58.
    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"
  • 59.
    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 %>
  • 60.
    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 %>
  • 61.
    Rendering Collections Railsdetermines 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
  • 62.
    Rendering Collections Railsdetermines 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 ra ils 3. <h1>Products</h1> 0 <%= render(@products) || ‘there are no products available.’ %> index.html.erb <p>Product Name: <%= product.name %></p> _product.html.erb
  • 63.
    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
  • 64.
    Local Variables render :partial=> "product", :collection => @products, :as => :item %> <%= render :partial => 'products', :collection => @products,            :as => :item, :locals => {:title => "Products Page"} %>
  • 65.
    Spacer Templates <%= render:partial => @products, :spacer_template => "product_ruler" %>
  • 66.
    Layouts • Application Layout •Controller Layout • Action Layout • Partial Layout
  • 67.
    Layouts layout view template <html> <% content_for :head do %>   <head>   <title>A simple page</   <%= yield :head %> title>   </head> <% end %>   <body>     <%= yield %> <p>Hello, Rails!</p>   </body> </html> yield placeholder yield(:head) content_for :head yield(:bar) content_for :bar
  • 68.
    Nested Layouts NewsController Layout ApplicationController Layout <% content_for :stylesheets do %> <html>   #top_menu {display: none} <head>   #right_menu {float: right; background-color:   <title><%= @page_title or 'Page Title' %></ yellow; color: black} title> <% end %>   <%= stylesheet_link_tag 'layout' %>   <style type="text/css"> <% content_for :content do %> <%= yield :stylesheets %>   <div id="right_menu">Right menu items here</ </style> div> </head>   <%= content_for?(:news_content) <body> ? yield(:news_content)   <div id="top_menu">Top menu items here</div> : yield %>   <div id="menu">Menu items here</div> <% end %>   <div id="content"> <%= content_for?(:content) ? yield(:content) <%= render :template => 'layouts/application' %> : yield %> </div> </body> </html>
  • 69.