前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Rails布局和视图渲染

Rails布局和视图渲染

作者头像
用户1515472
发布2019-07-24 14:20:24
3.3K0
发布2019-07-24 14:20:24
举报

创建响应

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

  • 调用 render 方法
  • 调用 redirect_to 方法
  • 调用 head 方法,向浏览器发送只含HTTP首部的响应

一个控制器:

代码语言:javascript
复制
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状态码。

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

代码语言:javascript
复制
def update
    @book = Book.find(params[:id])
    if @book.update(book_params)
        redirect_to @book
    else
        render "edit"
    end
end

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

代码语言:javascript
复制
render :edit

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

代码语言:javascript
复制
render "products/show"

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

代码语言:javascript
复制
render template: "products/show"

渲染任意文件

代码语言:javascript
复制
render file: "/u/apps/warehouse_app/current/app/views/products/show" 

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

代码语言:javascript
复制
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的网络服务。

代码语言:javascript
复制
render plain: "OK"

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

代码语言:javascript
复制
render html: "<p>hello, world</p>".html_safe

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

渲染JSON

代码语言:javascript
复制
render json: @product

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

渲染XML

代码语言:javascript
复制
render xml: @product

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

渲染javascript

代码语言:javascript
复制
render js: "alert('hello, rails')"

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

渲染原始的主体

代码语言:javascript
复制
render body: "raw"

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

render 方法的其它选项

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

  • :content_type
  • :layout
  • :location
  • :status
  • :formats

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

代码语言:javascript
复制
render file: filename, content_type: "application/rss"

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

代码语言:javascript
复制
render layout: "special_layout"

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

代码语言:javascript
复制
render layout: false

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

代码语言:javascript
复制
render xml: photo, location: photo_url(photo)

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

代码语言:javascript
复制
render status: 500
render status: :forbidden

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

代码语言:javascript
复制
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 声明,可以覆盖默认使用的布局约定:

代码语言:javascript
复制
class ProductsController < ApplicationController
    layout "inventory"
end

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

代码语言:javascript
复制
class ApplicationController < ActionController::Base
    layout "main"
end

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

代码语言:javascript
复制
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 选项,可以设定条件

代码语言:javascript
复制
class ProductsController < ApplicationController
    layout "product", except: [:index, :rss]
end
使用 redirect_to 方法

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

代码语言:javascript
复制
redirect_to photos_url

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

代码语言:javascript
复制
redirect_back(fallback_location: root_path)

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

代码语言:javascript
复制
redirect_to photos_path, status: 301
使用head方法

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

代码语言:javascript
复制
head :bad_request
head :created, location: photo_path(@photo)

布局的结构

静态资源标签辅助方法
  • aotu_discovery_link_tag
  • javascript_include_tag
  • stylesheet_link_tag
  • image_tag
  • video_tag
  • audio_tag
aotu_discovery_link_tag 链接到订阅源
代码语言:javascript
复制
<%= 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
复制
<%= javascript_include_tag "main" %>

Rails生成的script标签如下:

代码语言:javascript
复制
<script src="/assets/main.js"></script>

同时引入多个文件:

代码语言:javascript
复制
<%= javascript_include_tag "main", "columns" %>

引入外部文件:

代码语言:javascript
复制
<%= javascript_include_tag "http://example.com/main.js" %>
stylesheet_link_tag

类似于 javascript_include_tag

代码语言:javascript
复制
<%= stylesheet_link_tag "main" %>
代码语言:javascript
复制
<%= stylesheet_link_tag "main", "column" %>

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

代码语言:javascript
复制
<%= stylesheet_link_tag "main_print", media: "print" %>
image_tag

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

代码语言:javascript
复制
<%= image_tag "header.png" %>

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

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

代码语言:javascript
复制
<%= image_tag "home.gif" %>
<%= image_tag "home.gif", alt: "Home" %>
video_tag

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

代码语言:javascript
复制
<%= video_tag "movie.ogg" %>

生成

代码语言:javascript
复制
<video src="/videos/movie.ogg" />

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

代码语言:javascript
复制
<%= video ["trailer.ogg", "movie.ogg"] %>

生成

代码语言:javascript
复制
<video>
    <source src="trailer.ogg" />
    <source src="movie.ogg" />
</video>
audio_tag

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

代码语言:javascript
复制
<%= audio_tag "music.mp3" %>
yield

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

代码语言:javascript
复制
<html>
    <head></head>
    <body>
    <%= yield %>
    </body>
</html>

表明多个区域:

代码语言:javascript
复制
<html>
   <head>
    <%= yield %>
    </head>
    <body>
    <%= yield %>
    </body>
</html>

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

代码语言:javascript
复制
<% content_for :head do %>
   <title>A simple page</title>
<% end %>

<p>Hello, World!</p>

套入布局后生成:

代码语言:javascript
复制
<html>
  <head>
  <title>A simple page</title>
  </head>
  <body>
  <p>Hello, World!</p>
  </body>
</html>

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

使用局部视图
代码语言:javascript
复制
<%= render "menu" %>

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

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

代码语言:javascript
复制
<%= render partial: "link_area", layout: "graybar" %>

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

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

new.html.erb

代码语言:javascript
复制
<h1>New zone</h1>
<%= render partial: "form", locals: {zone: @zone} %>

edit.html.erb

代码语言:javascript
复制
<h1>Editing zone</h1>
<%= render partial: "form", locals: {zone: @zone} %>

_form.html.erb

代码语言:javascript
复制
<%= form_for(zone) do |f| %>
  <p>
    <b>Zone name</b><br>
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>

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

代码语言:javascript
复制
<%= render partial: "customer", object: @new_customer %>

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

代码语言:javascript
复制
<%= render @customer %>

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

代码语言:javascript
复制
<%= render partial: "product", collection: @products, as: :item %>
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 创建响应
    • 使用render方法
      • render 方法的其它选项
        • 查找布局
          • 使用 redirect_to 方法
            • 使用head方法
            • 布局的结构
              • 静态资源标签辅助方法
                • aotu_discovery_link_tag 链接到订阅源
                  • javascript_include_tag
                    • stylesheet_link_tag
                      • image_tag
                        • video_tag
                          • audio_tag
                            • yield
                              • 使用局部视图
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档