Your SlideShare is downloading. ×
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-t...
Fit Together                                               Request                                        ro              ...
Creating Response• Three HTTP responses by Controller ➡ call “render” : full response ➡ call “redirect_to” : redirect stat...
Default RenderingControllers automatically render  • views with names corresponding to valid     routes.  • {action_name}....
Default Rendering                    /books class BooksController < ApplicationController end                             ...
Default Rendering      resources :books                                               config/routes.rb$ rake routes CONTROL...
Default Rendering   class BooksController < ApplicationController     def index       @books = Book.all     end   end     ...
Default Rendering • app/views/books/index.html.erb    <h1>Listing Books</h1>         <table>      <tr>        <th>Title</t...
Using ‘Render’Many ways to customize rendering• Default view  : for a Rails template / a specific template / a file / inline...
Using ‘Render’     Rendering an Action’s viewdef update  @book = Book.find(params[:id])  if @book.update_attributes(params...
Using ‘Render’     Rendering an Action’s viewdef update  @book = Book.find(params[:id])  if @book.update_attributes(params...
Using ‘Render’     Rendering an Action’s viewdef update  @book = Book.find(params[:id])  if @book.update_attributes(params...
Using ‘Render’ Rendering an Action’s Template    from Another Controllerdef update  @book = Book.find(params[:id])  if @bo...
Using ‘Render’    Rendering an Arbitrary Filedef update  @book = Book.find(params[:id])  if @book.update_attributes(params...
Using ‘Render’                Wrapping it uprender :editrender :action => :editrender editrender edit.html.erbrender :acti...
Using ‘Render’                   with :inline                                              default type :ERBrender :inline...
Using ‘Render’                    with :textrender :text => "OK", :layout => true            short response to AJAX       ...
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/rs...
Options            for Render                     :layout optionrender :layout => special_layout                          ...
Options            for Render                   :location optionrender :xml => photo, :location => photo_url(photo)       ...
Options               for Render                           :status optionrender :status => 500render :status => :forbidden...
Status Code        Status Message        Symbol                      Status Code        Status Message           Symbol1xx...
Finding Layouts•   Rails first looks for a file in app/views/layouts    with the same base name as the controller.        ...
Finding Layouts      Specifying Layouts for Controllersclass ProductsController < ApplicationController  layout "inventory...
Finding Layouts          Choosing Layouts at Runtimeclass ProductsController < ApplicationController  layout :products_lay...
Finding Layouts          Choosing Layouts at Runtimeclass ProductsController < ApplicationController  layout Proc.new { |c...
Finding Layouts               Conditional Layoutsclass ProductsController < ApplicationController  layout "product", :only...
Finding Layouts               Layout Inheritance (1)        cascading downward‣ application_controller.rb class Applicatio...
Finding Layouts               Layout Inheritance (2)        cascading downward‣ special_posts_controller.rb class SpecialP...
Finding Layouts                                             cascading downward               Layout Inheritance (3)‣ old_p...
Using Redirect_to• redirect_to  - tell the browser to send a new request  for a different URL• cf. render  - a view templa...
Using Redirect_to                                         s : 30                                                          ...
Using Redirect_to                       Render vs Redirect_todef index                                   def index  @books...
Using Redirect_to             Render vs Redirect_todef index  @books = Book.allend def show  @book = Book.find_by_id(param...
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 GMTT...
Head-Only          Responseshead :created, :location => photo_path(@photo)HTTP/1.1 201 CreatedConnection: closeDate: Sun, ...
Structuring             LayoutsThree tools for knitting fragmented outputs   • Asset tags ( for asset links )   • yield an...
Structuring         Layouts            Asset Tag Helpers• auto_discovery_link_tag• javascript_include_tag    in <head> sec...
Structuring           Layouts                Asset Tag Helpers            auto_discovery_link_tag            RSS or ATOM f...
Structuring             Layouts                     Asset Tag Helpers                javascript_include_tag<%= javascript_...
javascript_include_tag<%= javascript_include_tag "main", "columns" %><%= javascript_include_tag "main", "/photos/columns" ...
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/...
javascript_include_tag :defaults :defaults expansion in config/application.rb    config.action_view.javascript_expansions[...
javascript_include_tag :all                          public/javascripts/*.*       <%= javascript_include_tag :all, :recurs...
stylesheet_link_tag assets/stylesheets/ with Asset Pipeline<%= stylesheet_link_tag "main" %><%= stylesheet_link_tag "main"...
stylesheet_link_tag :all public/stylesheets/ without Asset Pipeline<%= stylesheet_link_tag :all %><%= stylesheet_link_tag ...
image/video/audioAsset pipeline -   Asset pipeline +                   • app/assets/                                     i...
Yield    • a section where content from the view        should be inserted.                                 content_for<ht...
content_for                                            <html>                                              <head>         ...
Partial• breaking the render process into more  chunks• moving the code chunk to its own file• _partial.html.erb vs partial...
Partial<%= render "menu" %><%= render "shared/menu" %><%= render "shared/ad_banner" %> <h1>Products</h1> <p>Here are a few...
Local Variables<h1>New zone</h1><%= error_messages_for :zone %><%= render :partial => "form", :locals => { :zone =>@zone }...
A Partial variable  • a local variable with the same name as the     partial  • pass an object in to this local variable<%...
Rendering Collections Rails determines the name of the partial to use by looking at the model name in the collection. In f...
Rendering Collections Rails determines the name of the partial to use by looking at the model name in the collection. In f...
Heterogenous     Collections<h1>Contacts</h1><%= render [customer1, employee1, customer2, employee2] %>                   ...
Local Variablesrender :partial => "product",       :collection => @products,       :as => :item %><%= render :partial => p...
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>           ...
Nested Layouts     NewsController Layout                           ApplicationController Layout<% content_for :stylesheets...
감사합니다.
Upcoming SlideShare
Loading in...5
×

Layouts and Rendering in Rails, Season 2

3,624

Published on

Published in: Education

Transcript of "Layouts and Rendering in Rails, Season 2"

  1. 1. Ror lab. season 2 - the 12th round -Layouts and Rendering December 15th, 2012 Hyoseong Choi
  2. 2. Contents• Rendering methods• Layouts with multiple content sections• DRY using partial templates• Nested layouts( or sub-templates)
  3. 3. Fit Together Request ro ut er hea Controller vy ng cod deri es ren layout partial Model ViewDB Response
  4. 4. Creating Response• Three HTTP responses by Controller ➡ call “render” : full response ➡ call “redirect_to” : redirect status code ➡ call “head” : HTTP headers
  5. 5. Default RenderingControllers automatically render • views with names corresponding to valid routes. • {action_name}.html.erb
  6. 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. 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#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
  8. 8. Default Rendering class BooksController < ApplicationController   def index     @books = Book.all   end end • {action_name}.html.erbC oC : app/views/books/index.html.erb
  9. 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. 10. 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
  11. 11. 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
  12. 12. 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
  13. 13. 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
  14. 14. 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
  15. 15. 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
  16. 16. 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
  17. 17. Using ‘Render’ with :inline default type :ERBrender :inline =>  "<% products.each do |p| %><p><%= p.name %></p><% end%>"render :inline =>  "xml.p {Horrid coding practice!}", :type => :builder
  18. 18. Using ‘Render’ with :textrender :text => "OK", :layout => true short response to AJAX or web service requests
  19. 19. Using ‘Render’ with :jsonrender :json => @product built-in support for JSON
  20. 20. Using ‘Render’ with :xmlrender :xml => @product built-in support for XML
  21. 21. Using ‘Render’ with :jsrender :js => "alert(Hello Rails);" built-in support for XML
  22. 22. Options for Render• :content_type• :layout• :status• :location
  23. 23. Options for Render :content_type optionrender :file => filename, :content_type => application/rss Default MIME type :html - text/html :json - application/json :xml - application/xml
  24. 24. 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
  25. 25. Options for Render :location optionrender :xml => photo, :location => photo_url(photo) to set the HTTP Location header
  26. 26. Options for Render :status optionrender :status => 500render :status => :forbidden http://www.codyfauser.com/2008/7/4/rails-http-status-code-to-symbol-mapping
  27. 27. 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
  28. 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. 29. 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
  30. 30. 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
  31. 31. Finding Layouts Choosing Layouts at Runtimeclass ProductsController < ApplicationController  layout Proc.new { |controller|controller.request.xhr? ? popup : application }end using inline method!
  32. 32. Finding Layouts Conditional Layoutsclass ProductsController < ApplicationController  layout "product", :only => [:index, :rss]endclass ProductsController < ApplicationController  layout "product", :except => [:index, :rss]end
  33. 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. 34. Finding Layouts Layout Inheritance (2) cascading downward‣ special_posts_controller.rb class SpecialPostsController < PostsController   layout "special" end
  35. 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. 36. 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
  37. 37. Using Redirect_to s : 30 2 tatu lt s de fau Different Redirect Status Coderedirect_to photos_path, :status => 301
  38. 38. 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
  39. 39. 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
  40. 40. Head-Only Responses• render :nothing• a more obvious alternative ‘head’ method
  41. 41. 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
  42. 42. 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
  43. 43. Structuring LayoutsThree tools for knitting fragmented outputs • Asset tags ( for asset links ) • yield and content_for ( for layouts ) • Partials ( for refactoring )
  44. 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. 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. 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. 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. 48. Disable Asset Pipeline• config/application.rb # Enable the asset pipeline config.assets.enabled = true
  49. 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. 50. 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
  51. 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. 52. 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" %>
  53. 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. 54. 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/
  55. 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. 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. 57. 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
  58. 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. 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. 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. 61. 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
  62. 62. 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
  63. 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. 64. Local Variablesrender :partial => "product", :collection => @products, :as => :item %><%= render :partial => products, :collection => @products,           :as => :item, :locals => {:title => "Products Page"} %>
  65. 65. Spacer Templates<%= render :partial => @products, :spacer_template => "product_ruler" %>
  66. 66. Layouts• Application Layout• Controller Layout• Action Layout• Partial Layout
  67. 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. 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. 69. 감사합니다.
  70. 70.   ROR Lab.

×