Layouts and Rendering in Rails, Season 2
Upcoming SlideShare
Loading in...5

Layouts and Rendering in Rails, Season 2






Total Views
Views on SlideShare
Embed Views



8 Embeds 663 301 200
http://localhost 128 26 3 3 HTTP 1 1



Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
Post Comment
Edit your comment

Layouts and Rendering in Rails, Season 2 Layouts and Rendering in Rails, Season 2 Presentation Transcript

  • 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 ViewDB Response
  • Creating Response• Three HTTP responses by Controller ➡ call “render” : full response ➡ call “redirect_to” : redirect status code ➡ call “head” : HTTP headers
  • Default RenderingControllers 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#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
  • Default Rendering class BooksController < ApplicationController   def index     @books = Book.all   end end • {action_name}.html.erbC 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 viewdef update  @book = Book.find(params[:id])  if @book.update_attributes(params[:book])    redirect_to(@book)  else    render "edit"  end as a Stringend
  • Using ‘Render’ Rendering an Action’s viewdef update  @book = Book.find(params[:id])  if @book.update_attributes(params[:book])    redirect_to(@book)  else    render :edit  end as a Symbolend
  • Using ‘Render’ Rendering an Action’s viewdef 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 viewend
  • Using ‘Render’ Rendering an Action’s Template from Another Controllerdef 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 controllerend
  • Using ‘Render’ Rendering an Arbitrary Filedef 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
  • Using ‘Render’ Wrapping it uprender :editrender :action => :editrender editrender edit.html.erbrender :action => editrender :action => edit.html.erbrender books/editrender books/edit.html.erbrender :template => books/editrender :template => books/edit.html.erbrender /path/to/rails/app/views/books/editrender /path/to/rails/app/views/books/edit.html.erbrender :file => /path/to/rails/app/views/books/editrender :file => /path/to/rails/app/views/books/edit.html.erb
  • Using ‘Render’ with :inline default type :ERBrender :inline =>  "<% products.each do |p| %><p><%= %></p><% end%>"render :inline =>  "xml.p {Horrid coding practice!}", :type => :builder
  • Using ‘Render’ with :textrender :text => "OK", :layout => true short response to AJAX or web service requests
  • Using ‘Render’ with :jsonrender :json => @product built-in support for JSON
  • Using ‘Render’ with :xmlrender :xml => @product built-in support for XML
  • Using ‘Render’ with :jsrender :js => "alert(Hello Rails);" built-in support for XML
  • Options for Render• :content_type• :layout• :status• :location
  • Options for Render :content_type optionrender :file => filename, :content_type => application/rss Default MIME type :html - text/html :json - application/json :xml - application/xml
  • Options for Render :layout optionrender :layout => special_layout to tell Rails to use a specific file as the layout for the current actionrender :layout => false
  • Options for Render :location optionrender :xml => photo, :location => photo_url(photo) to set the HTTP Location header
  • Options for Render :status optionrender :status => 500render :status => :forbidden
  • Status Code Status Message Symbol Status Code Status Message Symbol1xx Informational 406 Not Acceptable :not_acceptable100 Continue :continue Proxy Authentication :proxy_authentication_req 407101 Switching Protocols :switching_protocols Required uired 408 Request Timeout :request_timeout102 Processing :processing  409 Conflict :conflict2xx Success 410 Gone :gone200 OK :ok 411 Length Required :length_required201 Created :created 412 Precondition Failed :precondition_failed202 Accepted :accepted 413 Request Entity Too Large :request_entity_too_large203 Non-Authoritative :non_authoritative_inform Information ation 414 Request-URI Too Long :request_uri_too_long204 No Content :no_content205 Reset Content :reset_content 415 Unsupported Media Type :unsupported_media_type206 Partial Content :partial_content 416 Requested Range Not :requested_range_not_sati207 Multi-Status :multi_status Satisfiable sfiable 417 Expectation Failed :expectation_failed226 IM Used :im_used 422 Unprocessable Entity :unprocessable_entity  423 Locked :locked3xx Redirection300 Multiple Choices :multiple_choices 424 Failed Dependency :failed_dependency301 Moved Permanently :moved_permanently 426 Upgrade Required :upgrade_required302 Found :found  303 See Other :see_other 5xx Server Error304 Not Modified :not_modified 500 Internal Server Error :internal_server_error305 Use Proxy :use_proxy307 Temporary Redirect :temporary_redirect 501 Not Implemented :not_implemented4xx Client Error 502 Bad Gateway :bad_gateway400 Bad Request :bad_request 503 Service Unavailable :service_unavailable401 Unauthorized :unauthorized 504 Gateway Timeout :gateway_timeout402 Payment Required :payment_required 505 HTTP Version Not :http_version_not_support403 Forbidden :forbidden Supported ed404 Not Found :not_found 507 Insufficient Storage :insufficient_storage405 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 Controllersclass ProductsController < ApplicationController  layout "inventory"  #...end app/views/layouts/inventory.html.erbclass ApplicationController < ActionController::Base  layout "main"  #...end app/views/layouts/main.html.erb
  • Finding Layouts Choosing Layouts at Runtimeclass 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 Runtimeclass ProductsController < ApplicationController  layout { |controller|controller.request.xhr? ? popup : application }end using inline method!
  • Finding Layouts Conditional Layoutsclass ProductsController < ApplicationController  layout "product", :only => [:index, :rss]endclass 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 templateredirect_to photos_urlredirect_to :back
  • Using Redirect_to s : 30 2 tatu lt s de fau Different Redirect Status Coderedirect_to photos_path, :status => 301
  • Using Redirect_to Render vs Redirect_todef index def index  @books = Book.all   @books = Book.allend 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   endend end a round trip to the browser
  • Using Redirect_to Render vs Redirect_todef 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 one stop rendering
  • Head-Only Responses• render :nothing• a more obvious alternative ‘head’ method
  • Head-Only Responseshead :bad_requestHTTP/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
  • Head-Only Responseshead :created, :location => photo_path(@photo)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
  • Structuring LayoutsThree 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 "" %><%= 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 "" %>
  • 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/audioAsset 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: <%= %></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: <%= %></p> _product.html.erb
  • Heterogenous Collections<h1>Contacts</h1><%= render [customer1, employee1, customer2, employee2] %> index.html.erb<p>Customer: <%= %></p> customers/_customer.html.erb<p>Employee: <%= %></p> employees/_employee.html.erb
  • Local Variablesrender :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>
  • 감사합니다.
  •    ROR Lab.