Rails布局和视图渲染

2018-05-08  本文已影响87人  忽如寄

创建响应

从控制器的角度,创建HTTP响应有三种方法:

一个控制器:

class BooksController < ApplicationController
    def index
        @books = Book.all
    end
end

基于“多约定,少配置”原则,在 index 动作末尾并没有指定要渲染的视图,Rails会自动在控制器的视图文件夹中寻找 action_name.html.erb 模板,然后渲染。这里渲染的就是 app/views/books/index.html.erb

使用render方法

render 方法的行为有多种定制方式,可以渲染Rails模板的默认视图、指定的模板、文件、行间代码或者什么也不渲染。渲染的内容可以是 文本JSON 或者 XML,而且可以设置响应的内容类型和HTTP状态码。

渲染同个控制器的其他模板

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

不想用字符串,也可以使用符号:

render :edit

渲染其他控制器的动作
使用 render 方法,指定模板的完整路径(相对于 app/views)即可。

render "products/show"

为了代码意图更加明显,还可以使用 :template 选项:

render template: "products/show"

渲染任意文件

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

想要渲染 views/books 下的 edit.html.erb 模板,以下方法都行:

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"

渲染纯文本
使用 :plain 选项,可以把没有标记语言的纯文本发给浏览器,这主要用于响应Ajax或无需使用HTML的网络服务。

render plain: "OK"

渲染HTML
使用 :html 选项可以把HTML字符串发送给浏览器:

render html: "<p>hello, world</p>".html_safe

如果没调用 html_safe 方法,HTML实体会转义

渲染JSON

render json: @product

在需要渲染的对象上无需调用 to_json 方法,使用了 :json 选项,render 方法会自动调用 to_json

渲染XML

render xml: @product

在需要渲染的对象上无需调用 to_xml 方法,使用了 :xml 选项,render 方法会自动调用 to_xml

渲染javascript

render js: "alert('hello, rails')"

此时发送给浏览器的字符串,其MIME类型就是 text/javascript

渲染原始的主体

render body: "raw"

这时候返回的类型是 text/html ,只有在不在意内容类型的时候才应该使用这个选项。大多数时候,使用 :plain:html 选项更加合适。

render 方法的其它选项

render 方法一般还可接受其他5个选项:

:content_type选项
默认情况下,Rails渲染得到的结果内容类型为 text/html,如果使用 :json 选项,内容类型为 application/json,如果使用 :xml 选项,则内容类型为 application/xml ,如果需要修改内容类型,可使用 :content_type 选项:

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

:layout 选项
render 方法大部分渲染得到的结果都会作为当前布局的一部分显示,:layout 选项指定使用特定的文件作为布局:

render layout: "special_layout"

当设置为 false 时,则说明不使用布局:

render layout: false

:location选项
用于设置HTTP的location首部:

render xml: photo, location: photo_url(photo)

:status选项
设定HTTP状态码,(在大多数情况下都是200),可以使用HTTP状态码,也可以使用状态码含义设定。

render status: 500
render status: :forbidden

:formats选项
改变格式,值可以是一个符号或者一个数组,默认使用 :html

render formats: :xml
render formats: [:json, :xml]

查找布局

查找布局时,首先在文件夹 app/views/layouts 文件夹中是否有和控制器同名的文件。例如,渲染 PhotosController 中的动作会使用 app/views/layouts/photo.html.erb 或者 app/views/layouts/photos.builder 。如果没有针对控制器的布局,Rails会使用 app/views/layouts/application.html.erbapp/views/layouts/application.builder 。如果没有 .erb 布局,Rails会使用 .builder 布局。

指定控制器的布局
在控制器中使用 layout 声明,可以覆盖默认使用的布局约定:

class ProductsController < ApplicationController
    layout "inventory"
end

若要指定整个应用使用的布局,可以在ApplicationController类中使用layout声明:

class ApplicationController < ActionController::Base
    layout "main"
end

在运行时选择布局
使用符号把布局延后到处理请求时再选择:

class ProductsController < ApplicationController
    layout :products_layout
    
    def show
        @product = Product.find(params[:id])
    end

    private
    def products_layout
        @current_user.special? ? "special" : "products"
end

现在,如果用户是特殊用户,会使用一个特殊的布局渲染。

根据条件设定布局
使用 :only:except 选项,可以设定条件

class ProductsController < ApplicationController
    layout "product", except: [:index, :rss]
end

使用 redirect_to 方法

redirect_to 方法告诉浏览器向另一个URL发起新请求:

redirect_to photos_url

可以使用 redirect_back 把用户带回他们之前所在的页面,页面地址从 http_referer 中获取,不过浏览器不一定会设定,所以需要设定 fallback_location

redirect_back(fallback_location: root_path)

默认 redirect_to 方法把HTTP状态码设为302,如果想要设定其他状态码,可以使用 :status 选项:

redirect_to photos_path, status: 301

使用head方法

head 方法只把首部发送给浏览器,参数是HTTP状态码数字,或者符号形式,选项是一个散列,指定首部的名称和对应的值

head :bad_request
head :created, location: photo_path(@photo)

布局的结构

静态资源标签辅助方法

aotu_discovery_link_tag 链接到订阅源

<%= auto_discovery_link_tag(:rss, {action: "feed"}, {title: "RSS Feed"}) %>

javascript_include_tag

Rails应用的javascript文件可以存放在三个位置: app/assetslib/assetsvendor/assets。文件的地址可使用相对文档根目录的完整路径或URL。例如,如果想链接到 app/assets、lib/assets 或 vendor/assets 文件夹中名为 javascripts 的子文件夹中的文件,可以这么做:

<%= javascript_include_tag "main" %>

Rails生成的script标签如下:

<script src="/assets/main.js"></script>

同时引入多个文件:

<%= javascript_include_tag "main", "columns" %>

引入外部文件:

<%= javascript_include_tag "http://example.com/main.js" %>

stylesheet_link_tag

类似于 javascript_include_tag

<%= stylesheet_link_tag "main" %>
<%= stylesheet_link_tag "main", "column" %>

默认情况下, stylesheet_link_tag 创建的链接属性为 media="screen" rel="stylesheet",指定相应的选项可以覆盖默认值:

<%= stylesheet_link_tag "main_print", media: "print" %>

image_tag

生成img标签,默认从 public/images 文件夹中加载文件:

<%= image_tag "header.png" %>

文件名必须指定图像的拓展名

同样可以通过散列指定HTML属性,另外如果没有 alt 属性,
Rails会使用图片的首字母大写的文件名(去掉拓展名)。

<%= image_tag "home.gif" %>
<%= image_tag "home.gif", alt: "Home" %>

video_tag

生成 <video> 标签,默认从 public/vedios 文件夹中加载文件。

<%= video_tag "movie.ogg" %>

生成

<video src="/videos/movie.ogg" />

同样也支持散列指定HTML属性。
把数组传递给 video_tag 方法可以指定多个视频

<%= video ["trailer.ogg", "movie.ogg"] %>

生成

<video>
    <source src="trailer.ogg" />
    <source src="movie.ogg" />
</video>

audio_tag

生成 <audio> 标签,默认从 public/audio 文件夹中加载

<%= audio_tag "music.mp3" %>

yield

在布局中,yield 标明一个区域,渲染的视图会插在这里,最简单的情况是只有一个 yield ,此时渲染的整个视图都会插入在这个区域:

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

表明多个区域:

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

视图的主体会插入未命名的yield区域,若想在具名yield中插入内容,可以使用 content_for 方法。

<% content_for :head do %>
   <title>A simple page</title>
<% end %>

<p>Hello, World!</p>

套入布局后生成:

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

如果不同区域需要不同的内容(sidebar、footer等),就可以使用 content_for 方法。

使用局部视图

<%= render "menu" %>

这会渲染名为 _menu.html.erb 的文件,局部视图的文件名都是以下划线开头的,以便和普通视图区分开,引用时无需加入下划线。

局部布局
与视图使用布局一样,局部视图也可以使用布局

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

这里会使用 _graybar.html.erb 布局渲染局部视图 _link_area.html.erb ,此时局部布局与局部视图保存在同一个文件夹中。

传递局部变量
局部变量可以传入局部视图,这样可以使得局部视图更加强大、更加灵活。

new.html.erb

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

edit.html.erb

<h1>Editing 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 %>

每个局部视图中都有一个和局部视图同名的局部变量,通过object选项可以把这个对象传给这个变量:

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

如果要在局部视图中渲染模型实例,可以使用简写:

<%= render @customer %>

如果要在局部视图中自定义局部变量的名字,可以使用 :as 选项指定:

<%= render partial: "product", collection: @products, as: :item %>
上一篇下一篇

猜你喜欢

热点阅读