官方文档:http://guides.rubyonrails.org/layouts_and_rendering.html

渲染 view

渲染 html.rb 与相应的 action controller

def update
@book = Book.find(params[:id])
if @book.update(book_params)
redirect_to(@book)
else
render "edit"
end
end

  

或者渲染 aciton

def update
@book = Book.find(params[:id])
if @book.update(book_params)
redirect_to(@book)
else
render :edit
end
end

  

渲染另一个不同的 controller

render "products/show"

  

或者更明确地写作

render template: "products/show"

  

渲染一个特别的文件

render file: "/u/apps/warehouse_app/current/app/views/products/show"

  

实际上,上面的都是实现同一个功能

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"

  

无 view 渲染

inline 默认应用 ERB 进行渲染

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

  

除了ERB之外,还可以指定 type

render inline: "xml.p {'Horrid coding practice!'}", type: :builder

  

渲染 plain text。默认不使用 layout

render plain: "OK"

  

渲染 html。不加 html_safe 默认转义

render html: "<strong>Not Found</strong>".html_safe

  

渲染 json 与 xml

render json: @product

render xml: @product

  

渲染 Vanilla js

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

  

渲染 raw body

render body: "raw"
设置具体选项

选项

:content_type
:layout
:location
:status
:formats

指定 content_type

默认 content_type 为 text/html (or application/json if you use the :json option, or application/xml for the :xml option.)

render file: filename, content_type: "application/rss"

指定 layout

render layout: "special_layout"

禁用 layout

render layout: false

设置 location

render xml: photo, location: photo_url(photo)

设置 status

rails 会自动设置 状态码,手动设置

render status: 500
render status: :forbidden
 

指定格式化类型

render formats: :xml
render formats: [:json, :xml]
 
Controller 指定 layout
class ProductsController < ApplicationController
layout "inventory"
#...
end

还可以限制 only 或 except。使用 only: 与 except:

class ProductsController < ApplicationController
layout "product", except: [:index, :rss]
end
 
模板嵌套

controller 嵌套

# in app/controllers/application_controller
class ApplicationController < ActionController::Base
end # in app/controllers/admin_controller
class AdminController < ApplicationController
end # in app/controllers/admin/products_controller
class Admin::ProductsController < AdminController
def index
end
end

admin/products#index action 的路由的查询顺序为

app/views/admin/products/
app/views/admin/
app/views/application/

避免渲染多次

def show
@book = Book.find(params[:id])
if @book.special?
render action: "special_show"
end
end
 
路由重定向
redirect_to photos_url

或者

redirect_back(fallback_location: root_path)

这个的路由的 location 以 HTTP_REFERER header  为准,如果没有设置这个 header,就会使用fallback的 location

这里调用 redirect_to时, Rails 默认使用 HTTP status code 302,作临时重定向 temporary redirect(网页不刷新,地址改变,这里使用的js Turbolinks替换,强迫地址改变)。可以手动指定 301 做永久重定向  permanent redirect (网页刷新,地址改变)

redirect_to photos_path, status: 301

对于

get '/stories', to: redirect { |path_params, req| "/articles/#{req.subdomain}" }

此处默认使用 301

render 与 redirect_to 区别

render action 不执行 action的代码。而 redirect_to 执行 action的代码。

比如:

此时使用 render直接返回到 index.html.erb 不执行 index action的代码,报错。

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

redirect_to 会返回一个 302 响应,浏览器接受响应并发起另一个请求 /books,执行 index acction的代码(查询数据库),非常耗时。

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

为避免二次请求,还是使用 render,并重新获取 @books:

def index
@books = Book.all
end def show
@book = Book.find_by(id: params[:id])
if @book.nil?
@books = Book.all
flash.now[:alert] = "Your book was not found"
render "index"
end
end

 

当 检测到 @book为空时,会重新计算 all the books,并 直接渲染  index.html.erb

此外,浏览器发出 flash的 alert信息告诉用法发生了什么。

结构化 Layout
Asset tags
yield and content_for
Partials
Asset Tag Helpers
auto_discovery_link_tag
javascript_include_tag
stylesheet_link_tag
image_tag
video_tag
audio_tag
yield and content_for

在 layout中定义 yield 与 yield :head

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

在页面中使用

<% content_for :head do %>
<title>A simple page</title>
<% end %> <p>Hello, Rails!</p>

则 html 的渲染结果为

<html>
<head>
<title>A simple page</title>
</head>
<body>
<p>Hello, Rails!</p>
</body>
</html>
Partials

直接 渲染,上面的 render 一个 partial  named _menu.html.erb

<%= render "menu" %>

设定 layout

这将使用 _graybar.html.erb 去渲染  _link_area.html.erb 这个 partial。

注意这里的 layout 不是 layouts 目录下的文件,而是与 partial 同目录下的文件。

<%= render partial: "link_area", layout: "graybar" %>

定义 locals (传递局部变量)

new.html.erb

<h1>New zone</h1>
<%= render partial: "form", locals: {zone: @zone} %>

_form.html.erb

<%= form_for(zone) do |f| %>
<p>
<b>Zone name</b><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>

 

渲染 Model

渲染到 customer 并且 object为 parent 里的 @new_customer

<%= render partial: "customer", object: @new_customer %>

直接渲染  _customer.html.erb ,objeect 为 parent里的 @customer

<%= render @customer %>
 
渲染 collection

index.html.erb

<h1>Products</h1>
<%= render partial: "product", collection: @products %>

_product.html.erb

<p>Product Name: <%= product.name %></p>

此外,index.html.erb 也可以简写:

<h1>Products</h1>
<%= render @products %>

  

直接渲染向量

index.html.erb

<h1>Contacts</h1>
<%= render [customer1, employee1, customer2, employee2] %>

customers/_customer.html.erb

<p>Customer: <%= customer.name %></p>

employees/_employee.html.erb

<p>Employee: <%= employee.name %></p>

为空处理

<h1>Products</h1>
<%= render(@products) || "There are no products available." %>

别名处理

<%= render partial: "product", collection: @products, as: :item %>
 

使用 根 Layout

app/views/layouts/application.html.erb

<html>
<head>
<title><%= @page_title or "Page Title" %></title>
<%= stylesheet_link_tag "layout" %>
<style><%= yield :stylesheets %></style>
</head>
<body>
<div id="top_menu">Top menu items here</div>
<div id="menu">Menu items here</div>
<div id="content"><%= content_for?(:content) ? yield(:content) : yield %></div>
</body>
</html>

  

app/views/layouts/news.html.erb

<% content_for :stylesheets do %>
#top_menu {display: none}
#right_menu {float: right; background-color: yellow; color: black}
<% end %>
<% content_for :content do %>
<div id="right_menu">Right menu items here</div>
<%= content_for?(:news_content) ? yield(:news_content) : yield %>
<% end %>
<%= render template: "layouts/application" %>

隐藏了顶部 menu,并增加了一个右部菜单。

这里 content_for?(:news_content) 维护了另一个 layout,如果不使用另一个子模板,可以仅仅使用 yield 替代。

05-08 15:35