Francis's Octopress Blog

A blogging framework for hackers.

Layouts and Rendering in Rails

Layouts and Rendering in Rails

Layouts and Rendering in Rails

This guide covers the basic layout features of Action Controller and Action View. By referring to this guide, you will be able to:

这个教程涵盖了Action Controller and Action View的基础布局。通过这个教程,你可以了解到如下内容:

  • Use the various rendering methods built into Rails 使用Rails内建的各种渲染方法
  • Create layouts with multiple content sections 使用多个content sections创建layouts
  • Use partials to DRY up your views 在你的view里面使用partials
  • Use nested layouts (sub-templates) 使用嵌套layoutssub-templates

1 Overview: How the Pieces Fit Together概述:如何完整的组合在一起

This guide focuses on the interaction between Controller and View in the Model-View-Controller triangle. As you know, the Controller is responsible for orchestrating the whole process of handling a request in Rails, though it normally hands off any heavy code to the Model. But then, when it’s time to send a response back to the user, the Controller hands things off to the View. It’s that handoff that is the subject of this guide.


In broad strokes, this involves deciding what should be sent as the response and calling an appropriate method to create that response. If the response is a full-blown view, Rails also does some extra work to wrap包裹the view in a layout and possibly to pull in partial views. You’ll see all of those paths later in this guide.


2 Creating Responses创建一个回应

From the controller’s point of view, there are three ways to create an HTTP response:

基于controllerview观点,这里有三种方法来创建一个HTTP response

  • Call render to create a full response to send back to the browser 调用一个render来创建以个完全回应full response回传给浏览器。
  • Call redirect_to to send an HTTP redirect status code to the browser 调用一个redirect_to来发送一个HTTP重定向状态码给浏览器
  • Call head to create a response consisting solely of HTTP headers to send back to the browser 调用head创建一个响应,只包括HTTP头并将其发送回浏览器

I’ll cover each of these methods in turn. But first, a few words about the very easiest thing that the controller can do to create a response: nothing at all.


2.1 Rendering by Default: Convention Over Configuration in Action以默认方式渲染:Action约定优于配置

You’ve heard that Rails promotes “convention over configuration”. Default rendering is an excellent example of this. By default, controllers in Rails automatically render views with names that correspond to valid routes. For example, if you have this code in your BooksController class:


rails generate scaffold Book title:string content:text


class BooksController < ApplicationController


And the following in your routes file:并且将下面的代码放入你的routes文件中:

resources :books

And you have a view file app/views/books/index.html.erb:

Rails will automatically render app/views/books/index.html.erb when you navigate to /books and you will see “Books are coming soon!” on your screen.

Rails将会自动渲染render app/views/books/index.html.erb当你导航到/books并且你将会看到在你的屏幕上会出现Books are coming soon!

However a coming soon screen is only minimally useful, so you will soon create your Book model and add the index action to BooksController:

无论如何a coming soon screen只是一个很小的用途,因此接着很快你将会创建你的Book模型并且添加index actionBooksController

class BooksController < ApplicationController

def index

@books = Book.all



Note that we dont have explicit render at the end of the index action in 按照accordance withconvention over configurationprinciple. The rule is that if you do not explicitly render something at the end of a controller action, Rails will automatically look for the action_name.html.erb template in the controllers view path and render it. So in this case, Rails will render the app/views/books/index.html.erb file.

注意按照约定优于配置原则,在index action结束的时候,我们没有明确的渲染。这里的规则是如果你在使用一个controller action结束的时候没有明确的render一些事物,Rails将会自动的在controller的视图目录中找到action_name.html.erb文件并渲染它。因此在这个例子中,Rails将会渲染app/views/books/index.html.erb文件。

If we want to display the properties of all the books in our view, we can do so with an ERB template like this:


<h1>Listing Books</h1>











<% @books.each do |book| %>


<td><%= book.title %></td>

<td><%= book.content %></td>

<td><%= link_to ‘Show’, book %></td>

<td><%= link_to ‘Edit’, edit_book_path(book) %></td>

<td><%= link_to ‘Remove’, book, :confirm => ‘Are you sure?’, :method => :delete %></td>


<% end %>



<br />


<%= link_to ‘New book’, new_book_path %>


The actual rendering is done by subclasses of ActionView::TemplateHandlers. This guide does not dig into that process, but it’s important to know that the file extension on your view controls the choice of template handler. In Rails 2, the standard extensions are .erb for ERB (HTML with embedded Ruby), and .builder for Builder (XML generator).

actual渲染是通过ActionView::TemplateHandlers的子类完成的。这个教程不会(深入)挖掘那个过程,但是知道一些文件存在在你的view controls,被选择用来做template handler这很重要。在Rails2ERBHTML with embedded Ruby)标准的扩展名是.erb,并且.builderBuilderXML生成器)的扩展名。

2.2 Using render

In most cases, the ActionController::Base#render method does the heavy lifting of rendering your application’s content for use by a browser. There are a variety of ways to customize the behaviour of render. You can render the default view for a Rails template, or a specific template, or a file, or inline code, or nothing at all. You can render text, JSON, or XML. You can specify the content type or HTTP status of the rendered response as well.

在大多数例子中,ActionController::Base#render方法通过浏览器将你的应用程序的内容生动的rendering给用户。这里有多种方法来定制render的习惯。你可以render一个Rails template为默认的视图,或者指定一个template,或者一个文件,或者一个内联代码,或者什么都没有。你可以render textJSON,或者XML。你可以指定上下文类型或者HTTP回应rendered的状态。

If you want to see the exact results of a call to render without needing to inspect检查it in a browser, you can call render_to_string. This method takes exactly the same options as render, but it returns a string instead of sending a response back to the browser.


2.2.1 Rendering Nothing

Perhaps the simplest thing you can do with render is to render nothing at all:

render :nothing => true

If you look at the response for this using cURL, you will see the following:


curl -I此命令就是访问HTTP status

$ curl -i

HTTP/1.1 200 OK

Connection: close

Date: Sun, 24 Jan 2010 09:25:18 GMT

Transfer-Encoding: chunked

Content-Type: /; charset=utf-8

X-Runtime: 0.014297

Set-Cookie: _blog_session=…snip…; path=/; HttpOnly

Cache-Control: max-age=0, private, must-revalidate

We see there is an empty response (no data after the Cache-Control line), but the request was successful because Rails has set the response to 200 OK. You can set the :status option on render to change this response. Rendering nothing can be useful for AJAX requests where all you want to send back to the browser is an acknowledgment that the request was completed.

def index


render :nothing => true,:status=>500



jhjguxin@jhjguxin-virtual-machine:~/blog$ curl -I


HTTP/1.1 300 Multiple Choices

HTTP/1.1 500 Internal Server Error


You should probably be using the head method, discussed later in this guide, instead of render :nothing. This provides additional额外flexibility灵活的and makes it explicit that youre only generating HTTP headers.(使用render :nothing提供了额外的灵活性它能够准确的只创建HTTP headers

2.2.2 Rendering an Action’s View渲染一个动作的视图

If you want to render the view that corresponds to a different action within the same template, you can use render with the name of the view:


def update

@book = Book.find(params[:id])

if @book.update_attributes(params[:book])



render “edit”



If the call to update_attributes fails, calling the update action in this controller will render the edit.html.erb template belonging to the same controller.

If you prefer如果你喜欢, you can use a symbol instead of a string to specify the action to render:

def update

@book = Book.find(params[:id])

if @book.update_attributes(params[:book])



render :edit



To be explicit, you can use render with the :action option (though this is no longer necessary in Rails 3.0):

def update

@book = Book.find(params[:id])

if @book.update_attributes(params[:book])



render :action => “edit”



Using render with :action is a frequent source of confusion for Rails newcomers. The specified action is used to determine which view to render, but Rails does not run any of the code for that action in the controller. Any instance variables that you require in the view must be set up in the current action before calling render.

使用render:action是来(处理)来自Rails的新访客的频繁混乱的(请求)。指定的action是用来决定渲染哪个视图,但是Rails并没有在controller中为那个action运行任何代码。不管在视图中的你请求的何种实例必须在调用render之前被set up到当前action中。

2.2.3 Rendering an Action’s Template from Another Controller从另一个controller渲染一个actionstemplate

What if you want to render a template from an entirely different controller from the one that contains the action code? You can also do that with render, which accepts the full path (relative to app/views) of the template to render. For example, if you’re running code in an AdminProductsController that lives in app/controllers/admin, you can render the results of an action to a template in app/views/products this way:


例如,你正在运行的代码在AdminProductsController存放在app/controllers/admin中你可以render一个action的结果到app/views/products 的一个template中用这样的方法: render ‘products/show’

Rails knows that this view belongs to a different controller because of the embedded slash character in the string. If you want to be explicit如果你想准确的表达, you can use the :template option (which was required on Rails 2.2 and earlier):

render :template => ‘products/show’

2.2.4 Rendering an Arbitrary File渲染任意文件

The render method can also use a view that’s entirely outside of your application (perhaps you’re sharing views between two Rails applications):


render “/u/apps/warehouse_app/current/app/views/products/show”

Rails determines that this is a file render because of the leading slash character斜线字符. To be explicit, you can use the :file option (which was required on Rails 2.2 and earlier):


render :file =>


The :file option takes an absolute file-system path. Of course, you need to have rights to the view that you’re using to render the content.


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’re running Rails on Microsoft Windows, you should use the :file option to render a file, because Windows filenames do not have the same format as Unix filenames.如果你正在Microsoft Windows中运行Rails,你应该使用:file选项来render一个文件,因为Windows文件名称与Unix文件名称并不相同(这里的文件名称应该包含了路径)。

2.2.5 Wrapping it up包装起来

The above three ways of rendering (rendering another template within the controller, rendering a template within another controller and rendering an arbitrary file on the file system) are actually variants of the same action.

这里总共有三种rendering的方法(在controllerrendering另一个template,使用另一个controller render一个template或者渲染一个文件系统上的任意类型的文件)实际上它们是相同action的变种。

In fact, in the BooksController class, inside of the update action where we want to render the edit template if the book does not update successfully, all of the following render calls would all render the edit.html.erb template in the views/books directory:

事实上,在BooksController类中,在update action中如果book没有更新成功的话我们希望render edit template,所有的后续render调用将会全部renderviews/books目录中的edit.html.erb(edit的各种render方式)

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’

Which one you use is really a matter of style and convention, but the rule of thumb is to use the simplest one that makes sense for the code you are writing.


2.2.6 Using render with :inline(使用):inlinerender

The render method can do without a view completely, if you’re willing to use the :inline option to supply ERB as part of the method call. This is perfectly valid:


render :inline =>

“<% products.each do |p| %><p><%= %></p><% end %>”


There is seldom很少any good reason to use this option. Mixing ERB into your controllers defeats the MVC orientation of Rails and will make it harder for other developers to follow the logic of your project. Use a separate单独erb view instead.



By default, inline rendering uses ERB. You can force it to use Builder instead with the :type option:

默认情况下,inline rendering使用ERB。你可以使用创建器强制替代它通过:type选项:

render :inline =>

“xml.p {‘Horrid coding practice!’}”, :type => :builder

2.2.7 Rendering Text渲染文本

You can send plain text – with no markup at all – back to the browser by using the :text option to render:


render :text => “OK”

Rendering pure text is most useful when you’re responding to AJAX or web service requests that are expecting something other than proper HTML.

Rendering纯文本在你回应到AJAZ或者web service请求的时候非常有用(因为)此时用户期待适当的HTML以外的东西。


By default, if you use the :text option, the text is rendered without using the current layout. If you want Rails to put the text into the current layout, you need to add the :layout => true option.


2.2.8 Rendering JSON渲染JSON

JSON is a JavaScript data format used by many AJAX libraries. Rails has built-in support for converting objects to JSON and rendering that JSON back to the browser:


render :json => @product

You don’t need to call to_json on the object that you want to render. If you use the :json option, render will automatically call to_json for you.


2.2.9 Rendering XML

Rails also has built-in support for converting objects to XML and rendering that XML back to the caller:

render :xml => @product

You don’t need to call to_xml on the object that you want to render. If you use the :xml option, render will automatically call to_xml for you.

2.2.10 Rendering Vanilla JavaScript渲染香草味的的JavaScript

Rails can render vanilla JavaScript:

render :js => “alert(‘Hello Rails’);”

This will send the supplied string to the browser with a MIME type of text/javascript.

2.2.11 Options for render

Calls to the render method generally accept four options:

  • :content_type
  • :layout
  • :status
  • :location The :content_type Option

By default, Rails will serve the results of a rendering operation with the MIME content-type of text/html (or application/json if you use the :json option, or application/xml for the :xml option.). There are times when you might like to change this, and you can do so by setting the :content_type option:

默认情况下,Rails将会帮助渲染操作通过使用text/htmlMIME content-type(或者如果你使用:json选项则是application/json,或者如果是:xml选项application/xml)。有时你可以改成这样,你可以通过设置:content_type选项达成:

render :file => filename, :content_type => ‘application/rss’ The :layout Option

With most of the options to render, the rendered content is displayed as part of the current layout. You’ll learn more about layouts and how to use them later in this guide.


You can use the :layout option to tell Rails to use a specific file as the layout for the current action:

render :layout => ‘special_layout’

You can also tell Rails to render with no layout at all:

render :layout => false The :status Option

Rails will automatically generate a response with the correct HTTP status code (in most cases, this is 200 OK). You can use the :status option to change this:

Rails将会自动生成(包含)正确的HTTP状态码的响应(在大多数情况,200 OK)。你可以使用:status选项来更改这些:

render :status => 500


render :status => :forbidden

Rails understands both numeric status codes and symbols for status codes. The :location Option

You can use the :location option to set the HTTP Location header:

render :xml => photo, :location => photo_url(photo)

2.2.12 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 (or app/views/layouts/photos.builder). If there is no such controller-specific layout, Rails will use app/views/layouts/application.html.erb or app/views/layouts/application.builder. If there is no .erb layout, Rails will use a .builder layout if one exists. Rails also provides several ways to more precisely assign specific layouts to individual controllers and actions.

要查找正确的layoutRails首先查找app/views/layouts中与controller base name相同的文件。For example, rendering actions from the PhotosController class will use app/views/layouts/photos.html.erb (or app/views/layouts/photos.builder). If there is no such controller-specific layout, Rails will use app/views/layouts/application.html.erb or app/views/layouts/application.builder. 如果没有找到.reblayoutRails将会使用一个.builder如果存在。Rails也提供一些方法来恰当的分派assign指定的layouts到个别的controllersactions Specifying Layouts on a per-Controller Basis

You can override the automatic layout conventions in your controllers by using the layout declaration in the controller. For example:


class ProductsController < ApplicationController

layout “inventory”


With this declaration, all methods within ProductsController will use app/views/layouts/inventory.html.erb for their layout.


To assign a specific layout for the entire application, use a declaration in your ApplicationController class:


class ApplicationController < ActionController::Base

layout “main”


With this declaration, all views in the entire application will use app/views/layouts/main.html.erb for their layout.通过这个声明,整个应用程序中的view将会使用app/views/layouts/main.html.erb作为他们的layout Choosing Layouts at Runtime在运行的时候选择layout

You can use a symbol to defer the choice of layout until a request is processed:


class ProductsController < ApplicationController

layout :products_layout


def show

@product = Product.find(params[:id])




def products_layout

@current_user.special? ? “special” : “products”




Now, if the current user is a special user, they’ll get a special layout when viewing a product. You can even use an inline method to determine the layout:


You can also decide the layout by passing a Proc object, the block you give the Proc will be given the controller instance, so you can make decisions based on the current request. For example:

你也可以通过一个Proc object来决定layout,你给出的Proc块将会被传递给controller实例,因此你可以在当前的请求的基础上作出(指定layout的)决定。

class ProductsController < ApplicationController

layout { |controller| controller.request.xhr? ? ‘popup’ : ‘application’ }


块里面的内容是什么意思呢? Conditional Layouts条件layouts

Layouts specified at the controller level support :only and :except options that take either a method name or an array of method names which correspond to method names within the controller:

controller级别的layouts指定支持:only and :except选项它们获取一个方法名或者一个方法名组成的数组它们对应于在controller中的方法名。

class ProductsController < ApplicationController

layout “product”, :except => [:index, :rss]


With this declaration, the product layout would be used for everything but the rss and index methods.

通过这个声明,product将会使用任何layout但是除了rssindex方法。 Layout Inheritance layout继承

Layouts are shared downwards in the hierarchy, and more specific layouts always override more general ones. For example:

  • application_controller.rb

class ApplicationController < ActionController::Base

layout “main”


  • posts_controller.rb

class PostsController < ApplicationController


  • special_posts_controller.rb

class SpecialPostsController < PostsController

layout “special”


  • old_posts_controller.rb

class OldPostsController < SpecialPostsController

layout nil


def show

@post = Post.find(params[:id])



def index

@old_posts = Post.older

render :layout => “old”



In this application:

  • 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.13 Avoiding Double Render Errors避免两次render错误

Sooner or later, most Rails developers will see the error message “Can only render or redirect once per action”. While this is annoying, it’s relatively easy to fix. Usually it happens because of a fundamental misunderstanding of the way that render works.

迟早,多大数Rails开发人员将会看到Can only render or redirect once per action”.当这恼人的(消息出现的时候),它相当容易修复。它发生的通常情况是因为对render工作方式的根本误解。

For example, here’s some code that will trigger this error:


def show

@book = Book.find(params[:id])

if @book.special?

render :action => “special_show”


render :action => “regular_show”


If @book.special? evaluates to true, Rails will start the rendering process to dump转储the @book variable into the special_show view. But this will not stop the rest of the code in the show action from running, and when Rails hits the end of the action, it will start to render the regular_show viewand throw an error. The solution is simple: make sure that you have only one call to render or redirect in a single code path. One thing that can help is and return. Here’s a patched version of the method:

def show

@book = Book.find(params[:id])

if @book.special?

render :action => “special_show” and return


render :action => “regular_show”


Make sure you use and return and not && return because while the former will work, the latter will not due to operator precedence in the Ruby Language.

确保你使用的是and return而不是&& return因为即使former将会工作,然而随后的却不会那是因为ruby语言中的运算优先操作。

irb(main):019:0> 1+3 and p 3+4


=> nil

irb(main):020:0> 1+3 && p 3+4

SyntaxError: compile error

(irb):20: syntax error, unexpected tINTEGER, expecting kDO or ‘{’ or ‘(’

1+3 && p 3+4


from (irb):20

from :0

irb(main):021:0> 1+3 &&(p 3+4)


=> nil

irb(main):022:0> false and 3+4

=> false

2.3 Using redirect_to使用重定向

Another way to handle returning responses to an HTTP request is with redirect_to. As you’ve seen, render tells Rails which view (or other asset) to use in constructing a response. The redirect_to method does something completely different: it tells the browser to send a new request for a different URL. For example, you could redirect from wherever you are in your code to the index of photos in your application with this call:


redirect_to photos_path

You can use redirect_to with any arguments that you could use with link_to or url_for. In addition, theres a special redirect that sends the user back to the page they just came from:这里是特殊的重定向发送(命令)给用户(的浏览器)回到原来的页面:

redirect_to :back

2.3.1 Getting a Different Redirect Status Code

Rails uses HTTP status code 302 (temporary redirect) when you call redirect_to. If you’d like to use a different status code (perhaps 301, permanent redirect), you can do so by using the :status option:


redirect_to photos_path, :status => 301

Just like the :status option for render, :status for redirect_to accepts both numeric and symbolic header designations名称.

2.3.2 The Difference Between render and redirect_to

Sometimes inexperienced developers conceive of redirect_to as a sort of goto command, moving execution from one place to another in your Rails code. This is not correct. Your code stops running and waits for a new request for the browser. It just happens that you’ve told the browser what request it should make next, by sending back an HTTP 302 status code.


Consider these actions to see the difference:

def index

@books = Book.all



def show

@book = Book.find_by_id(params[:id])

if @book.nil?

render :action => “index”



With the code in this form, there will likely be a problem if the @book variable is nil. Remember, a render :action doesnt run any code in the target action, so nothing will set up the @books variable that the index view is presumably可能depending on(实际验证结果也就是说@books为空). One way to fix this is to redirect instead of rendering:

def index

@books = Book.all



def show

@book = Book.find_by_id(params[:id])

if @book.nil?

redirect_to :action => :index



With this code, the browser will make a fresh request for the index page, the code in the index method will run, and all will be well.

The only downside to this code, is that it requires a round tripto the browser, the browser requested the show action with /books/1 and the controller finds that there are no books, so the controller sends out a 302 redirect response to the browser telling it to go to /books/, the browser complies依从and sends a new request back to the controller asking now for the index action, the controller then gets all the books in the database and renders the index template, sending it back down to the browser which then shows it on your screen.

这段代码仅有的缺点,是它需要浏览器兜一个圈,浏览器通过向服务器发送/books/1请求show action同时controller发现数据库没有这本书,因此controller发出一个302重定向响应给浏览器告诉它导航到/books/,浏览器依从(响应)并且发回一个新的请求来申请现在(进行)index actioncontroller随后从数据库中获取所有的books并且rendersindex template,发送它至浏览器然后在你的screen得到显示。

While in a small app, this added latency might not be a problem, it is something to think about when speed of response is of the essence本质. One way to handle this double request (though a contrived example) could be:


def index

@books = Book.all



def show

@book = Book.find_by_id(params[:id])

if @book.nil?

@books = Book.all

render “index”, :alert => ‘Your book was not found!’



Which would detect检测that there are no books, populate填充the @books instance variable with all the books in the database and then directly render the index.html.erb template returning it to the browser with a flash alert message telling the user what happened.

2.4 Using head To Build Header-Only Responses使用head来创建一个Header-Only响应

The head method can be used to send responses with only headers to the browser. It provides a more obvious alternative to calling render :nothing.它提供一个render :nothing明显的替代。The head method takes one parameter, which is interpreted解释执行as a hash of header names and values. For example, you can return only an error header:

head :bad_request

Which would produce the following header:

HTTP/1.1 400 Bad Request

Connection: close

Date: Sun, 24 Jan 2010 12:15:53 GMT

Transfer-Encoding: chunked

Content-Type: text/html; charset=utf-8

X-Runtime: 0.013483

Set-Cookie: _blog_session=…snip…; path=/; HttpOnly

Cache-Control: no-cache

Or you can use other HTTP headers to convey additional information:

或者你可以使用其他的HTTP headers来传递额外信息:

head :created, :location => photo_path(@photo)

Which would produce:这将会生成:

HTTP/1.1 201 Created

Connection: close

Date: Sun, 24 Jan 2010 12:16:44 GMT

Transfer-Encoding: chunked

Location: /photos/1

Content-Type: text/html; charset=utf-8

X-Runtime: 0.083496

Set-Cookie: _blog_session=…snip…; path=/; HttpOnly

Cache-Control: no-cache

3 Structuring Layouts结构布局

When Rails renders a view as a response, it does so by combining the view with the current layout (using the rules for finding the current layout that were covered earlier in this guide). Within a layout, you have access to three tools for combining different bits of output to form the overall response:


  • Asset tags
  • yield and content_for
  • Partials

3.1 Asset Tags标签资源

Asset tags provide methods for generating HTML that links views to feeds, JavaScript, stylesheets, images, videos and audios. These are the six asset tags available in Rails:

标签资产提供方法来创建HTML链接视图到feedsJavaScriptstylesheetsimagesvideosaudiosRails中有六个asset tags可用。

  • auto_discovery_link_tag
  • javascript_include_tag
  • stylesheet_link_tag
  • image_tag
  • video_tag
  • audio_tag

You can use these tags in layouts or other views, although the tags other than image_tag are most commonly used in the <head> section of a layout.

你可以使用这些tagslayout或者其他的views,即使tags image_tag超过通常使用的在layout<head>部分使用。

The asset tags do not verify the existence of the assets at the specified locations; they simply assume假设that you know what you’re doing and generate the link.

Asset tags并不验证asstes存在的性在specified locations;他们假设你知道他们正在做的什么并且生成链接。

3.1.1 Linking to Feeds with auto_discovery_link_tag

The auto_discovery_link_tag helper builds HTML that most browsers and newsreaders can use to detect the presences of RSS or ATOM feeds. It takes the type of the link (:rss or :atom), a hash of options that are passed through to url_for, and a hash of options for the tag:

对于auto_discovery_link_tag helper创建HTML,那些浏览器和新读者能够检测存在的RSS或者ATOM。它带有link类型的参数为(:rss or :atom),一个hash字典的选项可以通过它来指定url_for以及taghash选项。

<%= auto_discovery_link_tag(:rss, {:action => “feed”},

{:title => “RSS Feed”}) %>

There are three tag options available for auto_discovery_link_tag:

  • :rel specifies the rel value in the link (defaults to “alternate”)
  • :type specifies an explicit MIME type. Rails will generate an appropriate MIME type automatically.
  • :title specifies the title of the link


3.1.2 Linking to JavaScript Files with javascript_include_tag

The javascript_include_tag helper returns an HTML script tag for each source provided. Rails looks in public/javascripts for these files by default, but you can specify a full path relative to the document root, or a URL, if you prefer. For example, to include public/javascripts/main.js:

javascript_include_tag helper返回一个HTML script tag给每个提供的源。Rails默认在public/javascripts查找这些文件,但是你可以指定一个全路径关联到文档目录,或者一个URL,如果你喜欢。例如,要包含public/javascripts/main.js:

<%= javascript_include_tag “main” %>

To include public/javascripts/main.js and public/javascripts/columns.js:

<%= javascript_include_tag “main”, “columns” %>

To include public/javascripts/main.js and public/photos/columns.js:

<%= javascript_include_tag “main”, “/photos/columns” %>

To include

<%= javascript_include_tag “” %>

If the application does not use the asset pipeline, the :defaults option loads jQuery by default:


<%= javascript_include_tag :defaults %>

And you can in any case override the expansion in config/application.rb:


config.action_view.javascript_expansions[:defaults] = %w(foo.js bar.js)

When using :defaults, if an application.js file exists in public/javascripts it will be included as well at then end.


Also, the :all option loads every JavaScript file in public/javascripts:(不包含子目录)

<%= javascript_include_tag :all %>

Note that your defaults of choice will be included first, so they will be available to all subsequently随后included files.


You can supply the :recursive option to load files in subfolders of public/javascripts as well:

你也可以提供:recursive(递归)选项来导入在public/javascripts 子文件夹中的文件:

<%= javascript_include_tag :all, :recursive => true %>

If you’re loading multiple JavaScript files, you can create a better user experience by combining multiple files into a single download. To make this happen in production, specify :cache => true in your javascript_include_tag:

如果你正在导入多个的JavaScript文件,你可以创建一个更好的用户体验通过整合多个文件到一个单独的下载(all.js)。要得到这样的效果在产品中,在你的javascript_include_tag指定:cache => true

<%= javascript_include_tag “main”, “columns”, :cache => true %>

You can even use dynamic paths such as cache/#{current_site}/main/display.


3.1.3 Linking to CSS Files with stylesheet_link_tag

The stylesheet_link_tag helper returns an HTML <link> tag for each source provided. Rails looks in public/stylesheets for these files by default, but you can specify a full path relative to the document root, or a URL, if you prefer. For example, to include public/stylesheets/main.css:

stylesheet_link_tag helper返回一个HTML <link>标签给每一个提供的源。Rails默认在public/stylesheets查找这些文件,但是你可以指定一个全路径关联到文档目录,或者一个URL,如果你喜欢。例如,要导入public/stylesheets/main.css:

<%= stylesheet_link_tag “main” %>

To include public/stylesheets/main.css and public/stylesheets/columns.css:

<%= stylesheet_link_tag “main”, “columns” %>

To include public/stylesheets/main.css and public/photos/columns.css:

<%= stylesheet_link_tag “main”, “/photos/columns” %>

To include

<%= stylesheet_link_tag “” %>

By default, stylesheet_link_tag creates links with media=“screen” rel=“stylesheet” type=“text/css”. You can override any of these defaults by specifying an appropriate option (:media, :rel, or :type):

默认情况,stylesheet_link_tag创建links使用media=“screen” rel=“stylesheet” type=“text/css”。你可以覆盖这些默认设置的任何一个通过指定一个适当的选项(:media, :rel, or :type):

<%= stylesheet_link_tag “main_print”, :media => “print” %>

The all option links every CSS file in public/stylesheets:(不包含子目录)

<%= stylesheet_link_tag :all %>

You can supply the :recursive option to link files in subfolders of public/stylesheets as well:(递归导入public/stylesheets所有的样式

<%= stylesheet_link_tag :all, :recursive => true %>

If you’re loading multiple CSS files, you can create a better user experience by combining multiple files into a single download. To make this happen in production, specify :cache => true in your stylesheet_link_tag:(使用cache来改善用户体验)

<%= stylesheet_link_tag “main”, “columns”, :cache => true %>

By default, the combined file will be delivered as stylesheets/all.css. You can specify a location for the cached asset file instead:

默认情况下组合文件会交付为stylesheets/all.css。你可以指定一个lacationcached asset文件替代:

<%= stylesheet_link_tag “main”, “columns”,

:cache => ‘cache/main/display’ %>

You can even use dynamic paths such as cache/#{current_site}/main/display.

3.1.4 Linking to Images with image_tag

The image_tag helper builds an HTML <img /> tag to the specified file. By default, files are loaded from public/images.

image_tag helper对于指定的文件创建一个HTML <img />标签。默认情况,文件会从public/images被导入。



<%= image_tag “header.png” %>

You can supply a path to the image if you like:


<%= image_tag “icons/delete.gif” %>

You can supply a hash of additional HTML options:

<%= image_tag “icons/delete.gif”, {:height => 45} %>

You can also supply an alternate image to show on mouseover:你可以提供一个在鼠标经过的备用图像。

<%= image_tag “home.gif”, :onmouseover => “menu/home_highlight.gif” %>

You can supply alternate text for the image which will be used if the user has images turned off in their browser. If you do not specify an alt text explicitly, it defaults to the file name of the file, capitalized and with no extension. For example, these two image tags would return the same code:


<%= image_tag “home.gif” %>

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

You can also specify a special size tag, in the format “{width}x{height}”:

<%= image_tag “home.gif”, :size => “50x20” %>

In addition to the above special tags, you can supply a final hash of standard HTML options, such as :class, :id or :name:

<%= image_tag “home.gif”, :alt => “Go Home”,

:id => “HomeImage”,

:class => ‘nav_bar’ %>

3.1.5 Linking to Videos with video_tag

The video_tag helper builds an HTML 5 <video> tag to the specified file. By default, files are loaded from public/videos.

video_tag helper给指定文件创建一个HTML 5 <video>标签。默认的,文件会从public/videos被导入。

<%= video_tag “movie.ogg” %>


<video src=“/videos/movie.ogg” />

Like an image_tag you can supply a path, either absolute, or relative to the public/videos directory. Additionally you can specify the :size => “#{width}x#{height}” option just like an image_tag. Video tags can also have any of the HTML options specified at the end (id, class et al).

The video tag also supports all of the <video> HTML options through the HTML options hash, including:

video标签同样支持所有的<video> HTML选项通过HTML选项的hash字典,包含:

  • :poster => ‘image_name.png’, provides an image to put in place of the video before it starts playing.
  • :autoplay => true, starts playing the video on page load.
  • :loop => true, loops the video once it gets to the end.
  • :controls => true, provides browser supplied controls for the user to interact with the video.
  • :autobuffer => true, the video will pre load the file for the user on page load.

You can also specify multiple videos to play by passing an array of videos to the video_tag:

<%= video_tag [“trailer.ogg”, “movie.ogg”] %>

This will produce:

<video><source src=“trailer.ogg” /><source src=“movie.ogg” /></video>

3.1.6 Linking to Audio files with audio_tag

The audio_tag helper builds an HTML 5 <audio> tag to the specified file. By default, files are loaded from public/audios.

<%= audio_tag “music.mp3” %>

You can supply a path to the audio file if you like:

<%= audio_tag “music/first_song.mp3” %>

You can also supply a hash of additional options, such as :id, :class etc.

Like the video_tag, the audio_tag has special options:

  • :autoplay => true, starts playing the audio on page load
  • :controls => true, provides browser supplied controls for the user to interact with the audio.
  • :autobuffer => true, the audio will pre load the file for the user on page load.

3.2 Understanding yield未知的yield

Within the context of a layout, yield identifies a section where content from the view should be inserted. The simplest way to use this is to have a single yield, into which the entire contents of the view currently being rendered is inserted:

layoutcontext(上下文)中,yield表示一节来自view的内容将会被插入。最简单的方法来使用这个是有一个yield,视图的整个内容将会被rendered 插入。





<%= yield %>



You can also create a layout with multiple yielding regions:你也可以创建一个layout有多个yield区域。



<%= yield :head %>



<%= yield %>



The main body of the view will always render into the unnamed yield. To render content into a named yield, you use the content_for method.

视图的body将会总是render一个unnamed yield。要render内容给一个知名的yield,使用content_for方法。

3.3 Using content_for

The content_for method allows you to insert content into a named yield block in your layout. For example, this view would work with the layout that you just saw:


<% content_for :head do %>

<title>A simple page</title>

<% end %>


<p>Hello, Rails!</p>

The result of rendering this page into the supplied layout would be this HTML:



<title>A simple page</title>



<p>Hello, Rails!</p>



The content_for method is very helpful when your layout contains distinct regions such as sidebars and footers that should get their own blocks of content inserted. It’s also useful for inserting tags that load page-specific JavaScript or css files into the header of an otherwise generic layout.

3.4 Using Partials

Partial templates – usually just called “partials” – are another device for breaking the rendering process into more manageable chunks. With a partial, you can move the code for rendering a particular piece of a response to its own file.

Partial templates-通常被称为partials”-是另一个设备(单元)分解渲染过程到易于管理的多个块中。通过一个partial,你可以渲染了一个特定块的文件,通过respense这个文件来响应特定的代码。

3.4.1 Naming Partials命名Partials

To render a partial as part of a view, you use the render method within the view:

<%= render “menu” %>

This will render a file named _menu.html.erb at that point within the view being rendered. Note the leading underscore character: partials are named with a leading underscore下划线to distinguish区分them from regular views, even though they are referred to without the underscore. This holds true even when you’re pulling in a partial from another folder:


<%= render “shared/menu” %>

That code will pull in the partial from app/views/shared/_menu.html.erb.

3.4.2 Using Partials to Simplify Views

One way to use partials is to treat them as the equivalent of subroutines: as a way to move details out of a view so that you can grasp what’s going on more easily. For example, you might have a view that looked like this:

<%= render “shared/ad_banner” %>




<p>Here are a few of our fine products:</p>


<%= render “shared/footer” %>

Here, the ad_banner.html.erb and footer.html.erb partials could contain content that is shared among many pages in your application. You don’t need to see the details of these sections when you’re concentrating on a particular page.

For content that is shared among all pages in your application, you can use partials directly from layouts.

For content that is shared among all pages in your application, you can use partials directly from layouts.

3.4.3 Partial Layouts

A partial can use its own layout file, just as a view can use a layout. For example, you might call a partial like this:


<%= render :partial => “link_area”, :layout => “graybar” %>

This would look for a partial named link_area.html.erb and render it using the layout graybar.html.erb. Note that layouts for partials follow the same leading-underscore naming as regular partials, and are placed in the same folder with the partial that they belong to (not in the master layouts folder).


Also note that explicitly specifying :partial is required when passing additional options such as :layout.

3.4.4 Passing Local Variables

You can also pass local variables into partials, making them even more powerful and flexible. For example, you can use this technique to reduce duplication between new and edit pages, while still keeping a bit of distinct content:

  • new.html.erb

<h1>New zone</h1>

<%= error_messages_for :zone %>

<%= render :partial => “form”, :locals => { :zone => @zone } %>

  • edit.html.erb

<h1>Editing zone</h1>

<%= error_messages_for :zone %>

<%= render :partial => “form”, :locals => { :zone => @zone } %>

  • _form.html.erb

<%= form_for(zone) do |f| %>


<b>Zone name</b><br />

<%= f.text_field :name %>



<%= f.submit %>


<% end %>

Although the same partial will be rendered into both views, Action View’s submit helper will return “Create Zone” for the new action and “Update Zone” for the edit action.

Every partial also has a local variable with the same name as the partial (minus the underscore). You can pass an object in to this local variable via the :object option:

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

Within the customer partial, the customer variable will refer to引用@new_customer from the parent view.

In previous versions of Rails, the default默认情况local variable would look for an instance variable with the same name as the partial in the parent. This behavior was deprecated增加in 2.3 and has been removed in Rails 3.0.(可以自己添加如上)

If you have an instance of a model to render into a partial, you can use a shorthand syntax:

<%= render @customer %>

Assuming假设that the @customer instance variable contains an instance of the Customer model, this will use _customer.html.erb to render it and will pass the local variable customer into the partial which will refer to the @customer instance variable in the parent view.


3.4.5 Rendering Collections

Partials are very useful in rendering collections. When you pass a collection to a partial via the :collection option, the partial will be inserted once for each member in the collection:

  • index.html.erb


<%= render :partial => “product”, :collection => @products %>

  • _product.html.erb

<p>Product Name: <%= %></p>

When a partial is called with a pluralized collection, then the individual instances of the partial have access to the member of the collection being rendered via a variable named after the partial. In this case, the partial is product, and within the product partial, you can refer to product to get the instance that is being rendered.

当一个partial被通过一个多元的collection调用,然后partial 的个别的实例会访问collection的成员并开始被rendered通过一个在partial后面的变量名。在本例中the partial is product,并且在product partial中,你可以引用product来得到被开始渲染的实例。

In Rails 3.0, there is also a shorthand for this. Assuming @products is a collection of product instances, you can simply write this in the index.html.erb to produce the same result:

Rails 3.0中有一个快捷操作。假设@products是一个product实例的集合,你可以简单的在index.html.erb中写入下面的代码来产生相同的结果:


<%= render @products %>

Rails determines the name of the partial to use by looking at the model name in the collection. In fact, you can even create a heterogeneous合成collection and render it this way, and Rails will choose the proper partial for each member of the collection:

  • index.html.erb


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

  • customers/_customer.html.erb

<p>Customer: <%= %></p>

  • employees/_employee.html.erb

<p>Employee: <%= %></p>

In this case, Rails will use the customer or employee partials as appropriate for each member of the collection.

3.4.6 Local Variables

To use a custom local variable name within the partial, specify the :as option in the call to the partial:

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

With this change, you can access an instance of the @products collection as the item local variable within the partial.你可以访问item本地变量来访问@products collection的实例。


You can also pass in arbitrary local variables to any partial you are rendering with the :locals => {} option:

<%= render :partial => ‘products’, :collection => @products,

:as => :item, :locals => {:title => “Products Page”} %>

Would render a partial _products.html.erb once for each instance of product in the @products instance variable passing the instance to the partial as a local variable called item and to each partial, make the local variable title available with the value Products Page.

Rails also makes a counter variable available within a partial called by the collection, named after the member of the collection followed by _counter. For example, if youre rendering @products, within the partial you can refer to product_counter to tell you how many times the partial has been rendered. This does not work in conjunction结合with the :as => :value option.

You can also specify a second partial to be rendered between instances of the main partial by using the :spacer_template option:

3.4.7 Spacer Templates间隔templates

<%= render @products, :spacer_template => “product_ruler” %>

Rails will render the product_ruler partial (with no data passed in to it) between each pair of product partials.

3.5 Using Nested Layouts使用嵌套layouts

You may find that your application requires a layout that differs slightly略有不同from your regular application layout to support one particular controller. Rather than repeating the main layout and editing it, you can accomplish完成this by using nested layouts (sometimes called sub-templates). Here’s an example:

Suppose假设you have the following ApplicationController layout:

  • app/views/layouts/application.html.erb



<title><%= @page_title or ‘Page Title’ %></title>

<%= stylesheet_link_tag ‘layout’ %>

<style type=“text/css”><%= yield :stylesheets %></style>



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



On pages generated by NewsController, you want to hide the top menu and add a right menu:

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

<表达式1>?<表达式2>:<表达式3>; “?”运算符的含义是: 先求表达式1的值, 如果为真, 则执行表达式2,并返回表达式2的结果; 如果表达式1的值为假, 则执行表达式3 ,并返回表达式3的结果.

That’s it. The News views will use the new layout, hiding the top menu and adding a new right menu inside the “content” div.

There are several ways of getting similar results with different sub-templating schemes using this technique. Note that there is no limit in nesting levels. One can use the ActionView::render method via render :template => ‘layouts/news’ to base a new layout on the News layout. If you are sure you will not subtemplate the News layout, you can replace the content_for?(:news_content) ? yield(:news_content) : yield with simply yield.