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.

这个教程主要着重于在model-view-controller三角(关系)中的controllerview之间的交互。众所周知,controller是负责编排在Rails处理请求的全过程,通过这样它一般可以让model从沉重的代码中解放出来。但是接下来,什么时候是发回一个响应给用户呢,controller把事情交给view.这就是handoff这也是这个教程的主题。

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.

在广泛的划分情况下,这涉及到决定应该发送什么作为响应或者调用一个适当的方法来创建一个响应。如果这个响应是一个full-blownviewRails同样做一些额外的工作来在layout中包装视图或者有可能的话调入其他部分view。在后部分你将会看到完整的教程。

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.

我将会依次(介绍)每种方法。但在此之前,用少量的文字说明最简单的事情——controller创建一个回应:什么都没有。

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的原则约定优于配置。在这里默认的渲染是一个优秀的例子。默认情况中,Rails中的controllers自动渲染视图通过在routes中验证对应的视图名字。例如,如果你的(视图代码)在你的BooksController中:

rails generate scaffold Book title:string content:text

 

class BooksController < ApplicationController

end

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

end

end

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:

如果我们想在我们的视图中显示所有books的属性,我们可以这样做使用一个如下的ERB模板:

<h1>Listing Books</h1>

 

<table>

<tr>

<th>Title</th>

<th>Summary</th>

<th></th>

<th></th>

<th></th>

</tr>

 

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

<tr>

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

</tr>

<% end %>

</table>

 

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

如果你想查看调用一个render在浏览器中不需要检查的那些额外的结果。你可以调用render_to_string。这个方法获取和render完全的options,但是它返回的一个字符串而不是发送一个response回浏览器。

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查看回应,你将会看到如下内容:

curl -I 127.0.0.1:3000/books#此命令就是访问HTTP status

$ curl -i 127.0.0.1:3000/books

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

 

end

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

 

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:

如果你想render的视图对应着不同的action在一个相同的template中,你可以使用render加上视图的名字。

def update

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

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

redirect_to(@book)

else

render “edit”

end

end

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

redirect_to(@book)

else

render :edit

end

end

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

redirect_to(@book)

else

render :action => “edit”

end

end

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:

如果你想render一个template它的action来自完全不同的controller?你也可以使用render来(达到目的),它接收template的全路径(相对于app/views#项目路径为根目录)来render

例如,你正在运行的代码在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方法也可以使用一个完全脱离你的application的视图(可能你在两个Rails之间共享视图)

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

Rails认为这个是一个文件render是因为开头的斜线字符。更准确的(表示),你可以使用:file选项(它至少需要Rails2.2或者更高)。

render :file =>

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

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.

:file选项获取一个完全文件系统路径。当然,你需要有权限(查看)你正在渲染的视图。

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.

默认情况下,这个文件没有使用当前的layoutrender。如果你想Rails把这个文件渲染到当前layout,你需要添加:layout=>true选项。

 

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选项来提供ERBERB标签)作为方法调用(的参数)。这完全合法的:

render :inline =>

“<% products.each do |p| %><p><%= p.name %></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.

(很少有好的理由来使用这个选项)。在你的controllers中复杂的ERB使得你的Rails(应用程序)在MVC方面很失败,并且使得其他开发人员很难跟随你项目的逻辑。(最好)使用单个erb视图替代。

 

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选项:

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.

作为默认的,如果你是用:text选项,text并没有被render到当前layout。如果你希望Rails放置text到当前的layout,你需要添加:layout=>true选项。

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:

JSONJavaScript数据格式它被很多AJAX库使用。Rails内建支持转换对象成JSON并且rendering这些JSON反馈给浏览器:

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.

你不必对你renderobject调用to_json。如果你使用:json选项,render将会自动为你调用to_json

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

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

它是render的常见的选项,通过这个选项被rendered的内容被显示为当前layout的一部分。在本教程的随后部分你将了解更多的layouts的知识以及如何使用它们。

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

2.2.11.3 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

or

render :status => :forbidden

Rails understands both numeric status codes and symbols for status codes.

2.2.11.4 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

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

你可以通过在controller(类)中使用layout决定(指定的)layout来覆盖自动layout公约。例如:

class ProductsController < ApplicationController

layout “inventory”

end

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

通过这个声明,在ProductsController中所有的方法都将使用app/views/layouts/inventory.html.erb作为他们的layout

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

要分配一个指定的layout给整个application,在你的ApplicationController类(app/controllers/application_controller.rb使用一个声明:

class ApplicationController < ActionController::Base

layout “main”

end

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

2.2.12.2 Choosing Layouts at Runtime在运行的时候选择layout

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

你可以使用一个symbol来推迟选择的layout直到一个请求被处理:

class ProductsController < ApplicationController

layout :products_layout

 

def show

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

end

 

private

def products_layout

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

end

 

end

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:

现在,如果当前用户是一个特殊用户,他们将得到一个特殊的layout当其正在访问一个product。你甚至可以使用一个内联方法来确定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 Proc.new { |controller| controller.request.xhr? ? ‘popup’ : ‘application’ }

end

块里面的内容是什么意思呢?

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

end

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

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

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

end

  • posts_controller.rb

class PostsController < ApplicationController

end

  • special_posts_controller.rb

class SpecialPostsController < PostsController

layout “special”

end

  • old_posts_controller.rb

class OldPostsController < SpecialPostsController

layout nil

 

def show

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

end

 

def index

@old_posts = Post.older

render :layout => “old”

end

end

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”

end

render :action => “regular_show”

end

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

end

render :action => “regular_show”

end

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

7

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

7

=> 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来处理HTTP请求返回响应。正如你看到的,render通知Rails——视图(或者其他asset)使用其他(layout)结构来响应。redirect_to方法做一些完全不同的事情:它告诉浏览器发送一个新的请求给不同的URL。例如,无论你在你代码的哪里你可以重定向到photosindex,在你的应用程序中使用这个掉用:

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:

Rails使用HTTP状态代码301(临时重定向)当你调用redirect_to。如果你想使用一个不同的状态代码(可能是301,永久重定向),你可以通过使用:status选项:

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.

有时缺乏经验的开发人员心中构想的redirect_to就像一种goto命令,从你的Rails代码的一个地方移动到另一个地方执行。

Consider these actions to see the difference:

def index

@books = Book.all

end

 

def show

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

if @book.nil?

render :action => “index”

end

end

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

end

 

def show

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

if @book.nil?

redirect_to :action => :index

end

end

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:

然而在一个小的app,加载延迟不是问题,有时候是基于响应速度为主的考虑。一种方式来处理这个两次请求(通过一个人为的例子)可以像这样:

def index

@books = Book.all

end

 

def show

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

if @book.nil?

@books = Book.all

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

end

end

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:

Rails渲染一个视图作为响应,它这样做了通过联合视图和当前的layout(使用规则来查找当前的layout,它在这个教程的早期被介绍了)。在一个layout中,你访问三种工具来整合不同的输出块,以形成整体的回应:

  • 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

MIME类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

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 http://example.com/main.js:

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

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

如果应用程序没有使用asset管道,:defautls选项默认导入jQuery

<%= javascript_include_tag :defaults %>

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

并且你可以随意覆盖这个扩展在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.

如果使用:defaults,如果一个application.js文件存在于public/javascripts他将会同样被导入在随后。

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.

注意你默认的选择将会首先被inclueded,因此他们将于随后导入所有的文件。

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.

你可以使用多元路径例如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 http://example.com/main.css:

<%= stylesheet_link_tag “http://example.com/main.css” %>

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被导入。

Notethatyoumustspecifytheextensionoftheimage.PreviousversionsofRailswouldallowyoutojustusetheimagenameandwouldappend.pngifnoextensionwasgivenbutRails3.0doesnot.

注意你必须指定图像文件的扩展名。以前版本的Rails能够允许你仅仅使用图像文件名称就会被添加.png即使没有扩增名被给出。但是Rails3.0不这样了

<%= image_tag “header.png” %>

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

你可以给image提供一个路径如果你喜欢:

<%= 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它们将在用户的浏览器关闭图像(显示)的时候使用。如果你不准确的指定一个alt文本,它默认是文件的文件名,大写(首字母)并且没有扩展名。例如,下面的两个image标签将会返回同样的代码:

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

Produces生成

<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 插入。

<html>

<head>

</head>

<body>

<%= yield %>

</body>

</html>

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

<html>

<head>

<%= yield :head %>

</head>

<body>

<%= yield %>

</body>

</html>

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允许你插入内容到知名的yield块到你的layout

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

<html>

<head>

<title>A simple page</title>

</head>

<body>

<p>Hello, Rails!</p>

</body>

</html>

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一个名为menu.html.erb的文件在渲染视图的Partials插入点的时候。注意起始的下划线字符:partials被命名为以下划线()开始的规则来区分它们和视图,即使他们(的调用没有下划线)。这在你从除当前视图所在文件夹之外调入也一样成立:

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

 

<h1>Products</h1>

 

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

一个partial可以使用它们自己的layout文件,就像一个视图可以使用一个layout。例如你可以这样调用一个partial

<%= 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).

这将会查找一个名叫link_area.html.erbpartial并且在graybar.html.erbrender和使用它。

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

<p>

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

<%= f.text_field :name %>

</p>

<p>

<%= f.submit %>

</p>

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

假设@customer实例变量包含在一个Customer的实例中,这将会使用_customer.html.erbrender它并且传递本地变量customerpartial引用@customer实例变量的父视图。

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

<h1>Products</h1>

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

  • _product.html.erb

<p>Product Name: <%= 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中写入下面的代码来产生相同的结果:

<h1>Products</h1>

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

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

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

<html>

<head>

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

<%= stylesheet_link_tag ‘layout’ %>

<style type=“text/css”><%= 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>

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.