Rails Study(IV)Layouts and Rendering in Rails
1. Overview: How the Pieces Fit Together
The Controller hands things off to the View, and it normally hands off any heavy code to the Model.
2. Creating Responses
From the controller's point of view, there are three ways to create an HTTP response:
* call render to create a full response to send back to the browser
* call redirect_to to send an HTTP redirect status code to the browser
* call head to create a response consisting solely of HTTP headers to send back to the browser
2.1 Rendering by Default: Convention Over Configuration in Action
class BooksController < ApplicationController
end
resources :books
app/views/books/index.html.erb
URL is /books
def index
@books = Book.all
end
2.2 Using Render
2.2.1 Rendering Nothing
render :nothing => true
2.2.2 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
end
end
if the call to update_attributes fails, it will render the edit.html.erb template.
2.2.3 Rendering an Action's Template from Another Controller
render "products/show"
app/controllers/admin render to app/views/products
2.2.4 Rendering an Arbitrary File
The render method can also use a view that's entirely outside of your application.
render "/u/apps/warehouse_app/current/app/views/products/show"
This takes a absolute file-system path.
render :file => "/u/apps/warehouse_app/.." :layout => true
By default, the file is rendered without using the current layout. If you want Rails to put the file into the current layout, you need to
add the :layout => true option.
If you are running on Windows, you should use the :file option to render a file.
2.2.5 Wrapping it up.
2.2.6 Using render with :inline
render :inline =>
"<% products.each do |p| %><p><%= p.name %></p><% end %>"
2.2.7 Using render with :update
render :update do |page|
page.replace_html 'warning', "Invalid options supplied"
end
2.2.8 Rendering Text
send plain text.
render :text => "ok"
2.2.9 Rendering JSON
render :json => @product
2.2.10 Rendering XML
render :xml => @product
2.2.11 Rendering Vanilla JavaScript
Rails can render vanilla JavaScript (as an alternative to using update with an .rjs file)
render :js => "alert('Hello Rails');"
This will send the supplied string to the browser with a MIME type of text/javascript.
2.2.12 Option for render
Calls to the render method generally accept four options:
* :content_type
* :layout
* :status
* :location
2.2.12.1 The :content_type Option
render :file => filename, :content_type => 'application/rss'
2.2.12.2 The :layout Option
Use the :layout option to tell Rails to use a specific file as the layout for the current action
render :layout => 'special_layout'
Tell Rails to render with no layout at all:
render :layout => false
2.2.12.3 The :status Option
Rails will generate a response with correct HTML status code(in most cases, this is 200 OK.)
render :status => 500
render :status => :forbidden
2.2.12.4 The :location Option
Use :location option to set the HTTP location header
render :xml => photo, :location => photo_url(photo)
2.2.13 Finding Layouts
To find the current layout, Rails first looks for a file in app/views/layouts with the same base name as the controller.
For example, rendering actions from the PhotosController class will use app/views/layouts/photos.html.erb
If there is no file app/views/layouts/photos.html.erb, Rails will use app/views/layouts/application.html.erb.
2.2.13.1 Specifying Layouts on a per-Controller Basis
class ProductsController < ApplicationCon
layout "inventory"
end
with this declaration, all methods within ProductsController will use app/views/layouts/inventory.html.erb for their layout.
2.2.13.2 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
Now, if the current user is a special user, they'll get a special layout when viewing a product.
2.2.13.3 Conditional Layouts
class ProductsController < ApplicationController
layout "product", :except => [:index, :rss]
end
2.2.13.4 Layout Inheritance
application_controller.rb
class ApplicationController < ActionController::Base
layout "main"
end
posts_controller.rb
class PostsController < ApplicationController
end
special_posts_controller.rb
class SpecialPostsController < PostsController
layout "special"
end
old_posts_controller.rb
class OldPostsController < SpecialPostsController
layout nil
def show
@post = Post.find(params[:id])
end
def index
@old_posts = Post.older
render :layout => "old"
end
end
In general, views will be rendered in the main layout
PostsController#index will use the main layout
SpecialPostsController#index will use the special layout
OldPostsController#show will use no layout at all
OldPostsController#index will use the old layout
2.2.14 Avoiding Double Render Errors
def show
@book = Book.find(params[:id])
if @book.special?
render :action => "special_show" and return
end
render :action => "regular_show"
end
2.3 Using redirect_to
redirect_to tells the browser to send a new request for a different URL.
redirect_to photos_path #photos URL
redirect_to :back #back to the page they came from.
2.3.1 Getting a Different Redirect Status Code
redirect_to photos_path, :status => 301
2.3.2 The Difference Between render and 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
render is not right here, the @books is nil at that time.
def index
@books = Book.all
end
def show
@book = Book.find_by_id(params[:id])
if @book.nil?
redirect_to :action => :index
end
end
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
references:
http://guides.rubyonrails.org/layouts_and_rendering.html
http://guides.rubyonrails.org/active_record_querying.html
1. Overview: How the Pieces Fit Together
The Controller hands things off to the View, and it normally hands off any heavy code to the Model.
2. Creating Responses
From the controller's point of view, there are three ways to create an HTTP response:
* call render to create a full response to send back to the browser
* call redirect_to to send an HTTP redirect status code to the browser
* call head to create a response consisting solely of HTTP headers to send back to the browser
2.1 Rendering by Default: Convention Over Configuration in Action
class BooksController < ApplicationController
end
resources :books
app/views/books/index.html.erb
URL is /books
def index
@books = Book.all
end
2.2 Using Render
2.2.1 Rendering Nothing
render :nothing => true
2.2.2 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
end
end
if the call to update_attributes fails, it will render the edit.html.erb template.
2.2.3 Rendering an Action's Template from Another Controller
render "products/show"
app/controllers/admin render to app/views/products
2.2.4 Rendering an Arbitrary File
The render method can also use a view that's entirely outside of your application.
render "/u/apps/warehouse_app/current/app/views/products/show"
This takes a absolute file-system path.
render :file => "/u/apps/warehouse_app/.." :layout => true
By default, the file is rendered without using the current layout. If you want Rails to put the file into the current layout, you need to
add the :layout => true option.
If you are running on Windows, you should use the :file option to render a file.
2.2.5 Wrapping it up.
2.2.6 Using render with :inline
render :inline =>
"<% products.each do |p| %><p><%= p.name %></p><% end %>"
2.2.7 Using render with :update
render :update do |page|
page.replace_html 'warning', "Invalid options supplied"
end
2.2.8 Rendering Text
send plain text.
render :text => "ok"
2.2.9 Rendering JSON
render :json => @product
2.2.10 Rendering XML
render :xml => @product
2.2.11 Rendering Vanilla JavaScript
Rails can render vanilla JavaScript (as an alternative to using update with an .rjs file)
render :js => "alert('Hello Rails');"
This will send the supplied string to the browser with a MIME type of text/javascript.
2.2.12 Option for render
Calls to the render method generally accept four options:
* :content_type
* :layout
* :status
* :location
2.2.12.1 The :content_type Option
render :file => filename, :content_type => 'application/rss'
2.2.12.2 The :layout Option
Use the :layout option to tell Rails to use a specific file as the layout for the current action
render :layout => 'special_layout'
Tell Rails to render with no layout at all:
render :layout => false
2.2.12.3 The :status Option
Rails will generate a response with correct HTML status code(in most cases, this is 200 OK.)
render :status => 500
render :status => :forbidden
2.2.12.4 The :location Option
Use :location option to set the HTTP location header
render :xml => photo, :location => photo_url(photo)
2.2.13 Finding Layouts
To find the current layout, Rails first looks for a file in app/views/layouts with the same base name as the controller.
For example, rendering actions from the PhotosController class will use app/views/layouts/photos.html.erb
If there is no file app/views/layouts/photos.html.erb, Rails will use app/views/layouts/application.html.erb.
2.2.13.1 Specifying Layouts on a per-Controller Basis
class ProductsController < ApplicationCon
layout "inventory"
end
with this declaration, all methods within ProductsController will use app/views/layouts/inventory.html.erb for their layout.
2.2.13.2 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
Now, if the current user is a special user, they'll get a special layout when viewing a product.
2.2.13.3 Conditional Layouts
class ProductsController < ApplicationController
layout "product", :except => [:index, :rss]
end
2.2.13.4 Layout Inheritance
application_controller.rb
class ApplicationController < ActionController::Base
layout "main"
end
posts_controller.rb
class PostsController < ApplicationController
end
special_posts_controller.rb
class SpecialPostsController < PostsController
layout "special"
end
old_posts_controller.rb
class OldPostsController < SpecialPostsController
layout nil
def show
@post = Post.find(params[:id])
end
def index
@old_posts = Post.older
render :layout => "old"
end
end
In general, views will be rendered in the main layout
PostsController#index will use the main layout
SpecialPostsController#index will use the special layout
OldPostsController#show will use no layout at all
OldPostsController#index will use the old layout
2.2.14 Avoiding Double Render Errors
def show
@book = Book.find(params[:id])
if @book.special?
render :action => "special_show" and return
end
render :action => "regular_show"
end
2.3 Using redirect_to
redirect_to tells the browser to send a new request for a different URL.
redirect_to photos_path #photos URL
redirect_to :back #back to the page they came from.
2.3.1 Getting a Different Redirect Status Code
redirect_to photos_path, :status => 301
2.3.2 The Difference Between render and 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
render is not right here, the @books is nil at that time.
def index
@books = Book.all
end
def show
@book = Book.find_by_id(params[:id])
if @book.nil?
redirect_to :action => :index
end
end
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
references:
http://guides.rubyonrails.org/layouts_and_rendering.html
http://guides.rubyonrails.org/active_record_querying.html