美文网首页
Rails布局和视图渲染

Rails布局和视图渲染

作者: 忽如寄 | 来源:发表于2018-05-08 17:16 被阅读87次

    创建响应

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

    • 调用 render 方法

    • 调用 redirect_to 方法

    • 调用 head 方法,向浏览器发送只含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

    • :layout

    • :location

    • :status

    • :formats

    :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

    • javascript_include_tag

    • stylesheet_link_tag

    • image_tag

    • video_tag

    • audio_tag

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

    相关文章

      网友评论

          本文标题:Rails布局和视图渲染

          本文链接:https://www.haomeiwen.com/subject/fyewrftx.html