Layouts and Rendering
Ror lab. season 2
- the 12th round -
December 15th, 2012
Hyoseong Choi
Contents
•Rendering methods
•Layouts with multiple content sections
•DRY using partial templates
•Nested layouts( or sub-templates)
Fit Together
Controller
Model View
Request
Response
heavy codes
DB
router
rendering
layout partial
Creating Response
•Three HTTP responses by Controller
➡call “render” : full response
➡call “redirect_to” : redirect status code
➡call “head” : HTTP headers
Default Rendering
•views with names corresponding to valid
routes.
•{action_name}.html.erb
Controllers automatically render
Default Rendering
class BooksController < ApplicationController
end
BooksController
resources :books
config/routes.rb
<h1>Books are coming soon!</h1>
app/views/books/index.html.erb
/books
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
: app/views/books/index.html.erbCoC
Using ‘Render’
class BooksController < ApplicationController
def index
@books = Book.all
render “index”
render_to_string “index”
render :nothing => true
end
end
Many ways to customize rendering
•Default view
: for a Rails template / a specific template / a file / inline code /
nothing
•text / JSON / XML
Using ‘Render’
def update
@book = Book.find(params[:id])
if @book.update_attributes(params[ :book])
redirect_to( @book)
else
render "edit"
end
end
Rendering an Action’s viewas a String
Using ‘Render’
def update
@book = Book.find(params[:id])
if @book.update_attributes(params[ :book])
redirect_to( @book)
else
render :edit
end
end
Rendering an Action’s viewas a Symbol
Using ‘Render’
def update
@book = Book.find(params[:id])
if @book.update_attributes(params[ :book])
redirect_to( @book)
else
render :action => "edit"
end
end
Rendering an Action’s viewto render “edit” action’s view
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"
end
end
Rendering an Action’s Template
from Another Controllerfrom another controller
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
end
end
Rendering an Arbitrary File
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
Status Code Status Message Symbol
406 Not Acceptable :not_acceptable
407
Proxy Authentication
Required
:proxy_authentication_req
uired
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_sati
sfiable
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_support
ed
507 Insu"cient Storage :insu"cient_storage
510 Not Extended :not_extended
Status Code Status Message Symbol
1xx Informational1xx Informational1xx Informational
100 Continue :continue
101 Switching Protocols :switching_protocols
102 Processing :processing
2xx Success2xx Success2xx Success
200 OK :ok
201 Created :created
202 Accepted :accepted
203 Non-Authoritative
Information
:non_authoritative_inform
ation
204 No Content :no_content
205 Reset Content :reset_content
206 Partial Content :partial_content
207 Multi-Status :multi_status
226 IM Used :im_used
3xx Redirection3xx Redirection3xx Redirection
300 Multiple Choices :multiple_choices
301 Moved Permanently :moved_permanently
302 Found :found
303 See Other :see_other
304 Not Modified :not_modified
305 Use Proxy :use_proxy
307 Temporary Redirect :temporary_redirect
4xx Client Error4xx Client Error4xx Client Error
400 Bad Request :bad_request
401 Unauthorized :unauthorized
402 Payment Required :payment_required
403 Forbidden :forbidden
404 Not Found :not_found
405 Method Not Allowed :method_not_allowed
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
Finding Layouts
Specifying 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
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
class ApplicationController < ActionController::Base
layout "main"
end
‣application_controller.rb
class PostsController < ApplicationController
end
‣posts_controller.rb
Finding Layouts
Layout Inheritance (2)cascading downward
class SpecialPostsController < PostsController
layout "special"
end
‣special_posts_controller.rb
def index
@old_posts = Post.older
render :layout => "old"
end
# ...
end
‣old_posts_controller.rb
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
redirect_to photos_path, :status => 301
Different Redirect Status Codedefault status : 302
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?
render :action => "index"
end
end
def index
@books = Book.all
end
def show
@book = Book.find_by_id(params[ :id])
if @book.nil?
redirect_to :action => :index
end
endBSPVOEUSJQUPUIFCSPXTFS
Using Redirect_to
Render vs Redirect_toPOFTUPQSFOEFSJOH
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
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
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
head :created, :location => photo_path(@photo)
Structuring
Layouts
•Asset tags ( for asset links )
•yield and content_for ( for layouts )
•Partials ( for refactoring )
Three tools for knitting fragmented outputs
Structuring
Layouts
•auto_discovery_link_tag
•javascript_include_tag
•stylesheet_link_tag
•image_tag
•video_tag
•audio_tag
Asset Tag Helpersin <head> section in <body> section
Structuring
Layouts
Asset Tag Helpers
auto_discovery_link_tag
<%= auto_discovery_link_tag( :rss, {:action => "feed"},
{:title => "RSS Feed"}) %>RSS or ATOM feeds
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
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
<h1>Products</h1>
<%= render(@products) || ‘there are no products
available.’ %>
<p>Product Name: <%= product.name %></p>
index.html.erb
_product.html.erbrails
3.0