Francis's Octopress Blog

A blogging framework for hackers.

Action Controller Overview

Action Controller Overview


Action Controller Overview
This guide covers how controllers work and how they fit into the request cycle in your application. It includes sessions, filters, and cookies, data streaming, and dealing with exceptions raised by a request, among other topics.
Rails Routing from the Outside In
This guide covers the user-facing features of Rails routing. If you want to understand how to use routing in your own Rails applications, start here.

Action Controller Overview

In this guide you will learn how controllers work and how they fit into the request cycle in your application. After reading this guide, you will be able to:

在这个gudie中你将会学习到controllers是怎样工作的以及它们在你的应用程序中是怎用配合完成request cycle

  • Follow the flow of a request through a controller


  • Understand why and how to store data in the session or cookies


  • Work with filters to execute code during request processing


  • Use Action Controller’s built-in HTTP authentication

使用Action Controller的内置的HTTP认证

  • Stream data directly to the user’s browser

Stream data直接(到)用户的浏览器

  • Filter sensitive parameters so they do not appear in the application’s log


  • Deal with exceptions that may be raised during request processing


1 What Does a Controller Do?

Action Controller is the C in MVC. After routing has determined which controller to use for a request, your controller is responsible for making sense of the request and producing the appropriate output. Luckily, Action Controller does most of the groundwork for you and uses smart conventions to make this as straightforward as possible. Action ControllerMVC中的C。在routing已经决定了对于一个request使用哪个controller,你的controller负责请求的实际意图并且产生合适的输出。幸运的是,Action Controller为了做了大多数的基础工作并且使用智能方便的(方式)使得C能够尽可能的直接干脆。

For most conventional RESTful applications, the controller will receive the request (this is invisible to you as the developer), fetch or save data from a model and use a view to create HTML output. If your controller needs to do things a little differently, that’s not a problem, this is just the most common way for a controller to work.


A controller can thus be thought of as a middle man between models and views. It makes the model data available to the view so it can display that data to the user, and it saves or updates data from the user to the model.


For more details on the routing process, see RailsRoutingfromtheOutsideIn.

2 Methods and Actions

A controller is a Ruby class which inherits from ApplicationController and has methods just like any other class. When your application receives a request, the routing will determine which controller and action to run, then Rails creates an instance of that controller and runs the method with the same name as the action.


class ClientsController < ApplicationController

def new



As an example, if a user goes to /clients/new in your application to add a new client, Rails will create an instance of ClientsController and run the new method. Note that the empty method from the example above could work just fine because Rails will by default render the new.html.erb view unless the action says otherwise. The new method could make available to the view a @client instance variable by creating a new Client:

正如一个例子,如果一个user导航至/clients/new 在你的应用程序中添加一个new clientRails将会创建一个ClientsController的实例并且运行new方法。注意例子中空的方法完全可以工作因为Rails将会默认render名称为new.html.erb的视图除非action指定了另外的。new方法通过创建一个新的Client将使得可以查看@client实例变量。

def new

@client =


The Layouts&RenderingGuide explains this in more detail.

ApplicationController inherits from ActionController::Base, which defines a number of helpful methods. This guide will cover some of these, but if you’re curious to see what’s in there, you can see all of them in the API documentation or in the source itself.


Only public methods are callable as actions. It is a best practice to lower the visibility of methods which are not intended to be actions, like auxiliary methods or filters.


3 Parameters

You will probably want to access data sent in by the user or other parameters in your controller actions. There are two kinds of parameters possible in a web application. The first are parameters that are sent as part of the URL, called query string parameters. The query string is everything after “?” in the URL. The second type of parameter is usually referred to as POST data. This information usually comes from an HTML form which has been filled in by the user. It’s called POST data because it can only be sent as part of an HTTP POST request. Rails does not make any distinction between query string parameters and POST parameters, and both are available in the params hash in your controller:

在你的controller action中你可能想访问用户或者其他参数发送的数据。一个web应用程序中这里可能有两种参数。第一种是作为URL一部分发送的参数,叫做query string parameters(字符串查询参数)。查询字符串是在URL?”后面的所有字符。第二种类型的参数通常被简称为POST data。这类信息通常来至于一个被用户填写的HTML表单。它被称为POST data因为它仅能通过HTTP POST 请求的一部分发送。Rails在字符串查询参数和POST data参数之间不做任何区分,它们在你的controllerparams字典中都是可用的。

class ClientsController < ActionController::Base

This action uses query string parameters because it gets run

by an HTTP GET request, but this does not make any difference

to the way in which the parameters are accessed. The URL for

this action would look like this in order to list activated

clients: /clients?status=activated

def index

if params[:status] == “activated”

@clients = Client.activated


@clients = Client.unactivated




This action uses POST parameters. They are most likely coming

from an HTML form which the user has submitted. The URL for

this RESTful request will be “/clients”, and the data will be

sent as part of the request body.

def create

@client =[:client])


redirect_to @client


This line overrides the default rendering behavior, which

would have been to render the “create” view.

render :action => “new”




3.1 Hash and Array Parameters

The params hash is not limited to one-dimensional keys and values. It can contain arrays and (nested) hashes. To send an array of values, append an empty pair of square brackets “[]” to the key name:

params hash字典不限于一维的关键字和值。它能够包含数组和(嵌套)字典。要发送一个数组值,添加一个空的[]”key name

GET /clients?ids[]=1&ids[]=2&ids[]=3

The actual URL in this example will be encoded as/clients?ids%5b%5d=1&ids%5b%5d=2&ids%5b%5d=3as[and]are not allowed in URLs. Most of the time you don’t have to worry about this because the browser will take care of it for you, and Rails will decode it back when it receives it, but if you ever find yourself having to send those requests to the server manually you have to keep this in mind.但是如果你发现你自己不得不手动的发送这些请求到服务器你必须注意。

The value of params[:ids] will now be [“1”, “2”, “3”]. Note that parameter values are always strings; Rails makes no attempt to guess or cast the type.

To send a hash you include the key name inside the brackets:

<form accept-charset=“UTF-8” action=“/clients” method=“post”>

<input type=“text” name=“client[name]” value=“Acme” />

<input type=“text” name=“client[phone]” value=“12345” />

<input type=“text” name=“client[address][postcode]” value=“12345” />

<input type=“text” name=“client[address][city]” value=“Carrot City” />


When this form is submitted, the value of params[:client] will be {“name” =>Acme,phone=>12345,address=> {“postcode” =>12345,city=>Carrot City}}. Note the nested hash in params[:client][:address].

Note that the params hash is actually an instance of HashWithIndifferentAccess from Active Support, which acts like a hash that lets you use symbols and strings interchangeably互换as keys.

3.2 JSON/XML parameters

If you’re writing a web service application, you might find yourself more comfortable on accepting parameters in JSON or XML format. Rails will automatically convert your parameters into params hash, which you’ll be able to access like you would normally do with form data.

如果你打算写一个web服务程序,你可能会发现使用JSON或者XML格式接收参数会更加舒服。Rails将会自动的转换你的参数到params hash字典中,其中你将可以像正常表单数据那样接收数据。

So for example, if you are sending this JSON parameter:

{ "company": { "name": "acme", "address": "123 Carrot Street" } }

You’ll get params[:company] as { :name =>acme,address=>123 Carrot Street}.

Also, if you’ve turned on config.wrap_parameters in your initializer or calling wrap_parameters in your controller, you can safely omit the root element in the JSON/XML parameter. The parameters will be cloned and wrapped in the key according to your controller’s name by default. So the above parameter can be written as:

同样,如果你已经打开config.wrap_parameters在你的controller中初始化或者调用wrap_parameters,在JSON/XML参数中你可以安全的忽略root element。参数将会克隆和包装在key默认会依照你的controllername。因此完整的参数可以这样写:

{ "name": "acme", "address": "123 Carrot Street" }

And assume假设that youre sending the data to CompaniesController, it would then be wrapped in :company key like this:

{ :name => “acme”, :address => “123 Carrot Street”, :company => { :name => “acme”, :address => “123 Carrot Street” }}

You can customize the name of the key or specific parameters you want to wrap by consulting the APIdocumentation

3.3 Routing Parameters

The params hash will always contain the :controller and :action keys, but you should use the methods controller_name and action_name instead to access these values. Any other parameters defined by the routing, such as :id will also be available. As an example, consider a listing of clients where the list can show either active or inactive clients. We can add a route which captures the :status parameter in a “pretty” URL:

params hash字典总会包含关键字:controller and :action,但是你应该使用方法controller_name and action_name作为替代访问这些值。也有一些其他的值被routing定义,例如:id也是可以的。例如,思考一个clients的列表能够显示active或者inactive client。我们可以添加一个route它会捕获在aprettyURL(一个漂亮的URL)中的:status参数:

match ‘/clients/:status’ => ‘clients#index’, :foo => “bar”

In this case, when a user opens the URL /clients/active, params[:status] will be set to “active”. When this route is used, params[:foo] will also be set to “bar” just like it was passed in the query string. In the same way params[:action] will contain “index”.

3.4 default_url_options

You can set global default parameters that will be used when generating URLs with default_url_options. To do this, define a method with that name in your controller:

class ApplicationController < ActionController::Base

The options parameter is the hash passed in to ‘url_for’

def default_url_options(options)

{:locale => I18n.locale}



These options will be used as a starting-point when generating URLs, so it’s possible they’ll be overridden by url_for. Because this method is defined in the controller, you can define it on ApplicationController so it would be used for all URL generation, or you could define it on only one controller for all URLs generated there.

4 Session会话

Your application has a session for each user in which you can store small amounts of data that will be persisted between requests. The session is only available in the controller and the view and can use one of a number of different storage mechanisms:


  • CookieStore – Stores everything on the client.
  • DRbStore – Stores the data on a DRb server.
  • MemCacheStore – Stores the data in a memcache.
  • ActiveRecordStore – Stores the data in a database using Active Record.

All session stores use a cookie to store a unique ID for each session (you must use a cookie, Rails will not allow you to pass the session ID in the URL as this is less secure).


For most stores this ID is used to look up the session data on the server, e.g. in a database table. There is one exception, and that is the default and recommended session store – the CookieStore – which stores all session data in the cookie itself (the ID is still available to you if you need it). This has the advantage of being very lightweight and it requires zero setup in a new application in order to use the session. The cookie data is cryptographically signed to make it tamper-proof, but it is not encrypted, so anyone with access to it can read its contents but not edit it (Rails will not accept it if it has been edited).

大多数(时候)存储这个ID是用来在server上面查找session data,例如,存放在一个数据库table中。这里有一个例外,并且这是默认以及推荐的session存储-CookieStore-它存储所有的session数据在它的cookie中(如果你需要ID同样是可用的)。这里的优势是十分轻量级并且在一个新应用程序中使用session是零安装。cookie数据以加密签名的方式以防篡改,但是它没有将内容译成迷文,因此任何人访问它都可以阅读它的内容但是不能编辑它(Rails将不会接受被编辑过的cookie)。

The CookieStore can store around 4kB of datamuch less than the othersbut this is usually enough. Storing large amounts of data in the session is discouraged no matter which session store your application uses. You should especially avoid storing complex objects (anything other than basic Ruby objects, the most common example being model instances) in the session, as the server might not be able to reassemble them between requests, which will result in an error.


Read more about session storage in the SecurityGuide.

If you need a different session storage mechanism, you can change it in the config/initializers/session_store.rb file:


Use the database for sessions instead of the cookie-based default,

which shouldn’t be used to store highly confidential information

(create the session table with “script/rails g session_migration”)

YourApp::Application.config.session_store :active_record_store

Rails sets up a session key (the name of the cookie) when signing the session data. These can also be changed in config/initializers/session_store.rb:

Rails当注册session data的时候会设置一个session key(cookie的名字)。也可以在这里修改config/initializers/session_store.rb

Be sure to restart your server when you modify this file.


YourApp::Application.config.session_store :cookie_store, :key => ‘_your_app_session’

You can also pass a :domain key and specify the domain name for the cookie:


Be sure to restart your server when you modify this file.


YourApp::Application.config.session_store :cookie_store, :key => ‘_your_app_session’, :domain => “”

Rails sets up (for the CookieStore) a secret key密钥used for signing the session data. This can be changed in config/initializers/secret_token.rb

Be sure to restart your server when you modify this file.


Your secret key for verifying the integrity of signed cookies.

If you change this key, all old signed cookies will become invalid!

Make sure the secret is at least 30 characters and all random,

no regular words or you’ll be exposed to dictionary attacks.

YourApp::Application.config.secret_token = ‘49d3f3de9ed86c74b94ad6bd0…’

Changing the secret when using the CookieStore will invalidate废除all existing sessions.


4.1 Accessing the Session

In your controller you can access the session through the session instance method.


Sessions are lazily loaded. If you dont access sessions in your actions code, they will not be loaded. Hence因此you will never need to disable sessions, just not accessing them will do the job.

Session values are stored using key/value pairs like a hash:


class ApplicationController < ActionController::Base




Finds the User with the ID stored in the session with the key

:current_user_id This is a common way to handle user login in

a Rails application; logging in sets the session value and

logging out removes it.

def current_user

@_current_user ||= session[:current_user_id] &&




To store something in the session, just assign it to the key like a hash:


class LoginsController < ApplicationController

“Create” a login, aka “log the user in”

def create

if user = User.authenticate(params[:username], params[:password])

Save the user ID in the session so it can be used in

subsequent requests

session[:current_user_id] =

redirect_to root_url




To remove something from the session, assign that key to be nil:


class LoginsController < ApplicationController

“Delete” a login, aka “log the user out”

def destroy

Remove the user id from the session

@_current_user = session[:current_user_id] = nil

redirect_to root_url



To reset the entire session, use reset_session.从值整个session,使用reset_session

4.2 The Flash

The flash is a special part of the session which is cleared with each request. This means that values stored there will only be available in the next request, which is useful for storing error messages etc. It is accessed in much the same way as the session, like a hash. Let’s use the act of logging out as an example. The controller can send a message which will be displayed to the user on the next request:


class LoginsController < ApplicationController

def destroy

session[:current_user_id] = nil

flash[:notice] = “You have successfully logged out”

redirect_to root_url



Note it is also possible to assign a flash message as part of the redirection.

redirect_to root_url, :notice => “You have successfully logged out”

The destroy action redirects to the application’s root_url, where the message will be displayed. Note that it’s entirely up to the next action to decide what, if anything, it will do with what the previous action put in the flash. It’s conventional to display eventual errors or notices from the flash in the application’s layout:

destroy动作重定向到应用程序的root_url,在这里消息(刚添加的)将会被显示。注意:它完全取决于next action来决定做什么,如果有(next action),它将会完成previous action放入flash中的信息。


<!— <head/> —>


<% if flash[:notice] %>

<p><%= flash[:notice] %></p>

<% end %>

<% if flash[:error] %>

<p><%= flash[:error] %></p>

<% end %>

<!— more content —>



This way, if an action sets an error or a notice message, the layout will display it automatically


If you want a flash value to be carried over to another request, use the keep method:


class MainController < ApplicationController

Let’s say this action corresponds to root_url, but you want

all requests here to be redirected to UsersController#index.

If an action sets the flash and redirects here, the values

would normally be lost when another redirect happens, but you

can use ‘keep’ to make it persist for another request.

def index

Will persist all flash values.



You can also use a key to keep only some kind of value.


redirect_to users_url




By default, adding values to the flash will make them available to the next request, but sometimes you may want to access those values in the same request. For example, if the create action fails to save a resource and you render the new template directly, that’s not going to result in a new request, but you may still want to display a message using the flash. To do this, you can use in the same way you use the normal flash:

默认情况,添加到flash中的值在next request中是可用的,但是有时你可以想在同样的request中访问这些值。例如,如果create action保存resource失败并且你直接render new template,这样在一个newrequest中没有得到result,但是你仍然希望使用flash显示消息。这样做,你可以就像使用flash那样使用

class ClientsController < ApplicationController

def create

@client =[:client])


else[:error] = “Could not save client”

render :action => “new”




5 Cookies

Your application can store small amounts of data on the client — called cookies — that will be persisted across requests and even sessions. Rails provides easy access to cookies via the cookies method, which — much like the session — works like a hash:


class CommentsController < ApplicationController

def new

Auto-fill the commenter’s name if it has been stored in a cookie

@comment = => cookies[:commenter_name])



def create

@comment =[:comment])


flash[:notice] = “Thanks for your comment!”

if params[:remember_name]#:remember_name这里相当于用户的的反馈是否记住name

Remember the commenter’s name.

cookies[:commenter_name] =


Delete cookie for the commenter’s name cookie, if any.



redirect_to @comment.article


render :action => “new”




Note that while for session values you set the key to nil, to delete a cookie value you should use cookies.delete(:key).

6 Rendering xml and json data

ActionController makes it extremely easy to render xml or json data. If you generate a controller using scaffold then your controller would look something like this.

ActionController使得render xml或者json数据相当简单。如果你使用scaffold创建一个controller那么你的controller看起来将会像这样:

class UsersController < ApplicationController

def index

@users = User.all

respond_to do |format|

format.html # index.html.erb

format.xml { render :xml => @users}

format.json { render :json => @users}




Notice that in the above case code is render :xml => @users and not render :xml => @users.to_xml. That is because if the input is not string then rails automatically invokes to_xml .

注意在render中的完整示例代码是render :xml => @users并不是render :xml => @users.to_xml,那是因为如果输入的不是string那么rails自动调用to_xml

7 Filters过滤器

Filters are methods that are run before, after or “around” a controller action.

Filters是一个方法它运行在controller action之前或者伴随着controller action

Filters are inherited, so if you set a filter on ApplicationController, it will be run on every controller in your application.

Filters是可继承的,因此如果你在ApplicationController 设置了一个filter,他将会在你的应用程序的每个controller中运行。

Before filters may halt the request cycle. A common before filter is one which requires that a user is logged in for an action to be run. You can define the filter method this way:

filters之前可能会停止request周期。一个通常情况在filter之前的是用户logged inrequires使之对应的action被运行。你可以这样定义filter方法:

class ApplicationController < ActionController::Base

before_filter :require_login




def require_login

unless logged_in?

flash[:error] = “You must be logged in to access this section”

redirect_to new_login_url # halts request cycle




The logged_in? method simply returns true if the user is logged

in and false otherwise. It does this by “booleanizing” the

current_user method we created previously using a double ! operator.

Note that this is not common in Ruby and is discouraged unless you

really mean to convert something into true or false.

def logged_in?




The method simply stores an error message in the flash and redirects to the login form if the user is not logged in. If a before filter renders or redirects, the action will not run. If there are additional filters scheduled to run after that filter they are also cancelled.


In this example the filter is added to ApplicationController and thus all controllers in the application inherit it. This will make everything in the application requiretheusertobeloggedininordertouseit. For obvious reasons (the user wouldn’t be able to log in in the first place!), not all controllers or actions should require this. You can prevent this filter from running before particular actions with skip_before_filter:

明显的原因(在第一次登录的时候不能登录),并不是所有的controllers或者actions需要登录,你可以使用skip_before_filter 在部分action运行之前阻止这个filter

class LoginsController < ApplicationController

skip_before_filter :require_login, :only => [:new, :create]


Now, the LoginsController’s new and create actions will work as before without requiring the user to be logged in. The :only option is used to only skip this filter for these actions, and there is also an :except option which works the other way. These options can be used when adding filters too, so you can add a filter which only runs for selected actions in the first place.

现在,LoginsControllernewcreate action工作之前不再需要用户已经登录站点来。:only选项使用于仅仅在这些action中略过filter,同样这里也有:except选项一相反的方式工作。这些选项也可以在添加filters的时候使用,因此你可以添加一个filter其仅仅在选择的action第一次运行的时候执行(忽略)。

7.1 After Filters and Around Filters

In addition to before filters, you can also run filters after an action has been executed, or both before and after.


After filters are similar to before filters, but because the action has already been run they have access to the response data that’s about to be sent to the client. Obviously, after filters cannot stop the action from running.

After filters(执行action)和before filters类似,但是因为action已经被运行,这些filter会访问response data并且,response data会全部发送给client。明显的,after filters不能够停止action的运行。

Around filters are responsible for running their associated actions by yielding, similar to how Rack middlewares work.

Around filters能够通过yielding运行(Around filters执行的action的)关联的action,类似于Rack middlewares工作方式。

For example, in a website where changes have an approval workflow an administrator could be able to preview them easily, just apply them within a transaction:


class ChangesController < ActionController::Base

around_filter :wrap_in_transaction, :only => :show




def wrap_in_transaction

ActiveRecord::Base.transaction do




raise ActiveRecord::Rollback





Note that an around filter wraps also rendering. In particular, if in the example above the view itself reads from the database via a scope or whatever, it will do so within the transaction and thus present the data to preview.

注意around filter同样也会render。特别的是,如果在上述例子中,view自己通过一个scpoe或者其他从数据库中读取(数据),他将会在transaction中实现approval workflow并且将当前数据预览呈现。

They can choose not to yield and build the response themselves, in which case the action is not run.


7.2 Other Ways to Use Filters 过滤器的其他使用方式

While the most common way to use filters is by creating private methods and using *_filter to add them, there are two other ways to do the same thing.

即使通常使用过滤器的方式是创建私有的方法并且使用*_filteraround_filter :wrap_in_transaction, :only => :show)来添加他们,这里有两种其他的方法来做同样的事情。

The first is to use a block directly with the *_filter methods. The block receives the controller as an argument, and the require_login filter from above could be rewritten to use a block:

第一种方法是使用一个*_filter methodsblock(块)。这个block接收controller为一个参数,,并且从above(上下文中的上文)could be rewritten to use a block#这个例子中也是第一次登录无法完成,没有忽略登录action

class ApplicationController < ActionController::Base

before_filter do |controller|

redirect_to new_login_url unless controller.send(:logged_in?)



Note that the filter in this case uses send because the logged_in? method is private and the filter is not run in the scope of the controller. This is not the recommended way to implement this particular filter, but in more simple cases it might be useful.


The second way is to use a class (actually, any object that responds to the right methods will do) to handle the filtering. This is useful in cases that are more complex and can not be implemented in a readable and reusable way using the two other methods. As an example, you could rewrite the login filter again to use a class:

第二种方式是使用一个class(实际上,响应正确方法的任何对象都是可以的)来处理filtering。这在非常复杂的情况下,在只读不能implemented,重复使用两种其他方法是非常有用的。在例子中,你可以使用一个class来再次重写login filter

class ApplicationController < ActionController::Base

before_filter LoginFilter



class LoginFilter

def self.filter(controller)

unless controller.send(:logged_in?)

controller.flash[:error] = “You must be logged in”

controller.redirect_to controller.new_login_url




Again, this is not an ideal example for this filter, because it’s not run in the scope of the controller but gets the controller passed as an argument. The filter class has a class method filter which gets run before or after the action, depending on if it’s a before or after filter. Classes used as around filters can also use the same filter method, which will get run in the same way. The method must yield to execute the action. Alternatively, it can have both a before and an after method that are run before and after the action.

同样的,对于这种filter这不是一个(好)主意,因为它在controller的范围中不会运行但是获取controller为一个参数。filter 类有一个类方法filter,它在before或者after action运行,这依赖于它是一个before还是after filter。使用around filters的类同样也可以使用filter 方法,其也会以相同的方式运行。(filter)方法必须yield to 执行的action。另外,它也可以同时有beforeafter方法在before after action中运行。

8 Request Forgery Protection伪造请求保护

Cross-site request forgery is a type of attack in which a site tricks a user into making requests on another site, possibly adding, modifying or deleting data on that site without the user’s knowledge or permission.


The first step to avoid this is to make sure all “destructive” actions (create, update and destroy) can only be accessed with non-GET requests. If you’re following RESTful conventions you’re already doing this. However, a malicious site can still send a non-GET request to your site quite easily, and that’s where the request forgery protection comes in. As the name says, it protects from forged requests.

避免这样的事情发生的第一步是确保所有的destructive”(破坏性)actions(create, update and destroy)只能接受non-GET请求。如果你遵循RESTful公约你已经这样做了。然而,一个恶意的网站仍然可以轻易的发送一个non-GET请求到你的站点,到这里就该伪造请求保护(request forgery protection)出场了。正如名字所说,它防护伪造请求(对你站点的攻击)。

If you generate a form like this:如果你像下面这样生成表单:

<%= form_for @user do |f| %>

<%= f.text_field :username %>

<%= f.text_field :password %>

<% end %>

You will see how the token gets added as a hidden field:

你将会看到令牌是怎样作为一个hidden field添加:

<form accept-charset=“UTF-8” action=“/users/1” method=“post”>

<input type=“hidden”



<!— fields —>


Rails adds this token to every form that’s generated using the formhelpers, so most of the time you don’t have to worry about it. If you’re writing a form manually or need to add the token for another reason, it’s available through the method form_authenticity_token:

Rails为每个使用form helpers生成的form添加这样的令牌。因此大多数时间你不需要担心这样的问题。如果你打算手动编写一个form或者因为其他的原因需要添加令牌,这也是可以的通过form_authenticity_token方法来实现:


The SecurityGuide has more about this and a lot of other security-related issues that you should be aware of when developing a web application.

SecurityGuide 有更多的关于这些以及许多其他安全相关的问题(的解决方法)你在开发一个web application的时候应该保持清醒。

9 The Request and Response Objects

In every controller there are two accessor methods pointing to the request and the response objects associated with the request cycle that is currently in execution. The request method contains an instance of AbstractRequest and the response method returns a response object representing what is going to be sent back to the client.

在每个controller有两个指向与目前正在执行的请求周期相关的request response 对象的访问方法。request方法包含一个AbstractRequest的实例以及response方法返回一个response对象表示什么打算发送回client

9.1 The request Object

The request object contains a lot of useful information about the request coming in from the client. To get a full list of the available methods, refer to the APIdocumentation. Among the properties that you can access on this object are:



Property of request Purpose
host The hostname used for this request.
domain(n=2) The hostname’s first n segments, starting from the right (the TLD).
format The content type requested by the client.
method The HTTP method used for the request.
get?, post?, put?, delete?, head? Returns true if the HTTP method is GET/POST/PUT/DELETE/HEAD.
headers Returns a hash containing the headers associated with the request.
port The port number (integer) used for the request.
protocol Returns a string containing the protocol used plus “://”, for example “http://”.
query_string The query string part of the URL, i.e., everything after “?”.
remote_ip The IP address of the client.
url The entire URL used for the request.


9.1.1 path_parameters, query_parameters, and request_parameters

Rails collects all of the parameters sent along with the request in the params hash, whether they are sent as part of the query string or the post body. The request object has three accessors that give you access to these parameters depending on where they came from. The query_parameters hash contains parameters that were sent as part of the query string while the request_parameters hash contains parameters sent as part of the post body. The path_parameters hash contains parameters that were recognized by the routing as being part of the path leading to this particular controller and action.

Rails收集所有的parametersparams hash字典中于request一起发送,无论是作为query 字符串的一部分发送还是在post body中发送。request有三个访问器提供给你访问这些参数这依赖于它来自哪里。query_parameters hash字典包含作为查询字符串的一部分发送的参数,而request_parameters包含作为post body的一个部分发送的参数。path_parameters hash字典包含被routing组织作为指向特殊的controlleraction的参数。

9.2 The response Object

The response object is not usually used directly, but is during the execution of the action and rendering of the data that is being sent back to the user, but sometimes – like in an after filter – it can be useful to access the response directly. Some of these accessor methods also have setters, allowing you to change their values.

response object通常并不直接使用,但是它在action的执行与rendering的数据被发送回给用户期间建立,但是有的时候——像在一个after filter——它在直接访问responseobject)会非常有用。这些访问器中的一些methods也有setters,允许你改变它们的值。


Property of response Purpose
body This is the string of data being sent back to the client. This is most often HTML.
status The HTTP status code for the response, like 200 for a successful request or 404 for file not found.
location The URL the client is being redirected to, if any.
content_type The content type of the response.
charset The character set being used for the response. Default is “utf-8”.
headers Headers used for the response.


9.2.1 Setting Custom Headers

If you want to set custom headers for a response then response.headers is the place to do it. The headers attribute is a hash which maps header names to their values, and Rails will set some of them automatically. If you want to add or change a header, just assign it to response.headers this way:

response.headers[“Content-Type”] = “application/pdf”

10 HTTP Authentications

Rails comes with two built-in HTTP authentication mechanisms:

  • Basic Authentication
  • Digest Authentication

10.1 HTTP Basic Authentication

HTTP basic authentication is an authentication scheme that is supported by the majority of browsers and other HTTP clients. As an example, consider an administration section which will only be available by entering a username and a password into the browser’s HTTP basic dialog window. Using the built-in authentication is quite easy and only requires you to use one method, http_basic_authenticate_with.

基于HTTP的认证是一个认证结构它被主流的浏览器以及其他的HTTP clients支持。作为一个例子,思考一个管理员section它仅仅可以输入usernamepassword到浏览器的基于HTTP对话框窗口。使用内建的认证是十分简单的仅仅需要你使用一个方法,http_basic_authenticate_with

class AdminController < ApplicationController

http_basic_authenticate_with :name => “humbaba”, :password => “5baa61e4”


With this in place, you can create namespaced controllers that inherit from AdminController. The filter will thus be run for all actions in those controllers, protecting them with HTTP basic authentication.

通过将这段代码,你可以创建继承至AdminControllernamespaced controller。过滤器将自动对这些controllers中的所有的action运行这样的(认证),使用基于HTTP的认证来保护它们。

##in demo

class PostsController < ApplicationController

http_basic_authenticate_with :name => “test”, :password => “123456”, :except => :index


10.2 HTTP Digest Authentication

HTTP digest authentication is superior to the basic authentication as it does not require the client to send an unencrypted password over the network (though HTTP basic authentication is safe over HTTPS). Using digest authentication with Rails is quite easy and only requires using one method, authenticate_or_request_with_http_digest.

HTTP 精简认证优于基础认证因为它不需要client发送一个未加密的穿过网络(即使HTTP基础的认证比HTTPS更安全)。在Rails中使用 digest authentication相当容易并且仅仅需要使用一个方法,authenticate_or_request_with_http_digest

class AdminController < ApplicationController

USERS = { “lifo” => “world” }


before_filter :authenticate




def authenticate

authenticate_or_request_with_http_digest do |username|





As seen in the example above, the authenticate_or_request_with_http_digest block takes only one argument – the username. And the block returns the password. Returning false or nil from the authenticate_or_request_with_http_digest will cause authentication failure.

正如上面看到例子, authenticate_or_request_with_http_digest代码块仅仅获取一个参数——username。并且blockdo…end之间的block)返回password。从 authenticate_or_request_with_http_digest返回false或者nil将会导致认证失败。

11 Streaming and File Downloads

Sometimes you may want to send a file to the user instead of rendering an HTML page. All controllers in Rails have the send_data and the send_file methods, which will both stream data to the client. send_file is a convenience method that lets you provide the name of a file on the disk and it will stream the contents of that file for you.


To stream data to the client, use send_data:

require “prawn”

class ClientsController < ApplicationController

Generates a PDF document with information on the client and

returns it. The user will get the PDF as a file download.

def download_pdf

client = Client.find(params[:id])

send_data generate_pdf(client),

:filename => “#{}.pdf”,

:type => “application/pdf”





def generate_pdf(client) do

text, :align => :center

text “Address: #{client.address}”

text “Email: #{}”




The download_pdf action in the example above will call a private method which actually generates the PDF document and returns it as a string. This string will then be streamed to the client as a file download and a filename will be suggested to the user. Sometimes when streaming files to the user, you may not want them to download the file. Take images, for example, which can be embedded into HTML pages. To tell the browser a file is not meant to be downloaded, you can set the :disposition option to “inline”. The opposite and default value for this option is “attachment”.

上面例子中的 download_pdf action将会call一个私有的方法这个方法实际上创建PDF文档并且将其作为一个string形式返回。这个string将会随后以stream的形式到client作为一个文件下载并且一个文件名将会建议给用户。提到图形,例如,它可以被嵌入HTML页面。要告诉浏览器一个文件不是(用来)被下载的,你可以设置:disposition选项为‘inline’。这个选项相反的和默认的值是”attachment”

11.1 Sending Files

If you want to send a file that already exists on disk, use the send_file method.


class ClientsController < ApplicationController

Stream a file that has already been generated and stored on disk.

def download_pdf

client = Client.find(params[:id])


:filename => “#{}.pdf”,

:type => “application/pdf”)



This will read and stream the file 4kB at the time, avoiding loading the entire file into memory at once. You can turn off streaming with the :stream option or adjust the block size with the :buffer_size option.

这将会readstream文件一次4kB,避免一次将整个文件导入内存。你可以用:stream选项关闭流传送使或者设置适当的block size通过:buffer_size选项。

Be careful when using data coming from the client (params, cookies, etc.) to locate the file on disk, as this is a security risk that might allow someone to gain access to files they are not meant to see.



It is not recommended that you stream static files through Rails if you can instead keep them in a public folder on your web server. It is much more efficient to let the user download the file directly using Apache or another web server, keeping the request from unnecessarily going through the whole Rails stack. Although if you do need the request to go through Rails for some reason, you can set the :x_sendfile option to true, and Rails will let the web server handle sending the file to the user, freeing up the Rails process to do other things. Note that your web server needs to support the X-Sendfile header for this to work.

并不推荐你stream静态文件通过Rails如果作为替代你可以存放他们在你的服务器的一个公共的文件夹中。直接使用Apache或者其他web服务器让用户下载这些文件更加有效,避免不必要的request通过整体的Rails堆栈。即使如果因为某些原因你需要request通过Rails,你可以设置:x_sendfile option to trueRails将会让web server handle发送这些文件给用户,释放Rails进程去做其他的事情。注意你的web server需要支持 X-Sendfile header来做这个工作。

11.2 RESTful Downloads

While send_data works just fine, if you are creating a RESTful application having separate actions for file downloads is usually not necessary. In REST terminology, the PDF file from the example above can be considered just another representation of the client resource. Rails provides an easy and quite sleek way of doing “RESTful downloads”. Here’s how you can rewrite the example so that the PDF download is a part of the show action, without any streaming:

send_data工作良好,如果你正在创建的一个RESTful应用程序有单独的actions来做file下载通常是不需要的。在REST术语中,来自例子中的PDF文件完全可以被认为仅仅另一种client资源的代表。Rails提供一个容易和相当光滑的方式“RESTful downloads”来做这些。这里重写例子以便于PDF下载是show action的一部分,没有任何的streaming

class ClientsController < ApplicationController

The user can request to receive this resource as HTML or PDF.

def show

@client = Client.find(params[:id])


respond_to do |format|


format.pdf { render :pdf => generate_pdf(@client) }




In order for this example to work, you have to add the PDF MIME type to Rails. This can be done by adding the following line to the file config/initializers/mime_types.rb:

为了是这个例子能够工作,你必须添加 PDF MIME typeRails。可以添加下面的代码行到 config/initializers/mime_types.rb

Mime::Type.register “application/pdf”, :pdf

Configuration files are not reloaded on each request, so you have to restart the server in order for their changes to take effect.

Now the user can request to get a PDF version of a client just by adding “.pdf” to the URL:

GET /clients/1.pdf

12 Parameter Filtering

Rails keeps a log file for each environment in the log folder. These are extremely useful when debugging what’s actually going on in your application, but in a live application you may not want every bit of information to be stored in the log file. You can filter certain request parameters from your log files by appending them to config.filter_parameters in the application configuration. These parameters will be marked [FILTERED] in the log.

Rail对于每个环境保留一个log文件在log文件夹中。这些文件相当有用,在当你调试的时候他们是在你应用程序中实际运行的记录,但是在一个live的应用程序中你可以不希望每bit的信息都被存储在log文件中。你可以从你的log文件中过滤某些request parameters,通过添加它们到 config.filter_parametersapplication configurationThese parameters will be marked [FILTERED] in the log.

config.filter_parameters << :password

13 Rescue挽救

Most likely your application is going to contain bugs or otherwise throw an exception that needs to be handled. For example, if the user follows a link to a resource that no longer exists in the database, Active Record will throw the ActiveRecord::RecordNotFound exception.

就像你的应用程序包含某些bugs或者另一方面抛出一个异常需要被处理。例如,如果用户follows一个link到一个在数据库中并不存在的resourece,Active Record将会抛出 ActiveRecord::RecordNotFound异常。

Rails’ default exception handling displays a “500 Server Error” message for all exceptions. If the request was made locally, a nice traceback and some added information gets displayed so you can figure out what went wrong and deal with it. If the request was remote Rails will just display a simple “500 Server Error” message to the user, or a “404 Not Found” if there was a routing error or a record could not be found. Sometimes you might want to customize how these errors are caught and how they’re displayed to the user. There are several levels of exception handling available in a Rails application:

Rails的默认异常处理方式是对于所有的异常显示一个“500 Server Error”消息。如果request(相关的定制)在服务器被生成,一个漂亮的traceback以及添加一些信息来显示使得你可以指出什么地方出错了并且怎样处理它。如果requestremote Rails将会仅仅显示一个简单的“500 Server Error” 消息给用户,或者如果这里有一个routing错误或者一个记录不能被发现“404 Not Found”将会发送给用户。有时你可以能希望定制这些错误怎样引起以及为什么它们被显示给用户。在Rails应用程序中这里有一些级别的异常处理可用:

13.1 The Default 500 and 404 Templates

By default a production application will render either a 404 or a 500 error message. These messages are contained in static HTML files in the public folder, in 404.html and 500.html respectively. You can customize these files to add some extra information and layout, but remember that they are static; i.e. you can’t use RHTML or layouts in them, just plain HTML.

通过一个默认生成的应用程序将会render一个404或者500错误消息。这些消息被包含在public文件夹的静态HTML文件中,分别在 404.html and 500.html。你可以定制这些文件来添加一些其他的信息和layout,但是记住他们是静态的;i.e. you can’t use RHTML or layouts in them, 仅仅是纯HTML

13.2 rescue_from

If you want to do something a bit more elaborate when catching errors, you can use rescue_from, which handles exceptions of a certain type (or multiple types) in an entire controller and its subclasses.

如果你想做一些事情在catching 错误的时候做多一点的阐述,你可以使用 rescue_from,其处理一种明确的异常类型(或者多种)在整个controller以及它的子类中。

When an exception occurs which is caught by a rescue_from directive, the exception object is passed to the handler. The handler can be a method or a Proc object passed to the :with option. You can also use a block directly instead of an explicit Proc object.

当一个异常发生其会直接引发 rescue_from,这个exception对象被传递给handler。这个handler可以是一个方法或者一个被传递给:with选项的Proc对象。你也可以直接使用一个block替代准确的Proc对象。

Here’s how you can use rescue_from to intercept all ActiveRecord::RecordNotFound errors and do something with them.

这里是你如何使用 rescue_from来截取所有的ActiveRecord::RecordNotFound errors并且为其做一些事情。

class ApplicationController < ActionController::Base

rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found




def record_not_found

render :text => “404 Not Found”, :status => 404



Of course, this example is anything but elaborate and doesn’t improve on the default exception handling at all, but once you can catch all those exceptions you’re free to do whatever you want with them. For example, you could create custom exception classes that will be thrown when a user doesn’t have access to a certain section of your application:


class ApplicationController < ActionController::Base

rescue_from User::NotAuthorized, :with => :user_not_authorized




def user_not_authorized

flash[:error] = “You don’t have access to this section.”

redirect_to :back




class ClientsController < ApplicationController

Check that the user has the right authorization to access clients.

before_filter :check_authorization


Note how the actions don’t have to worry about all the auth stuff.

def edit

@client = Client.find(params[:id])





If the user is not authorized, just throw the exception.

def check_authorization

raise User::NotAuthorized unless current_user.admin?



Certain exceptions are only rescuable from the ApplicationController class, as they are raised before the controller gets initialized and the action gets executed. See Pratik Naik’s article on the subject for more information.

14 Force HTTPS protocol强制HTTPS协议

Sometime you might want to force a particular controller to only be accessible via an HTTPS protocol for security reason. Since Rails 3.1 you can now use force_ssl method in your controller to enforce that:

有时候因为安全原因你可能希望强制特定的cotroller仅仅在HTTPS协议下是可访问的。从Rails 3.1你可以在你的controller使用 force_ssl来强制执行:

class DinnerController



Just like the filter, you could also passing :only and :except to enforce the secure connection only to specific actions.

class DinnerController

force_ssl :only => :cheeseburger


force_ssl :except => :cheeseburger


Please note that if you found yourself adding force_ssl to many controllers, you may found yourself wanting to force the whole application to use HTTPS instead. In that case, you can set the config.force_ssl in your environment file.

请注意如果你发现你自己的添加 force_ssl到许多controllers,你可能发现你自己希望强制整个应用程序使用HTTPS替代。因为这样的原因,你可以在你的环境文件中设置config.force_ssl

controller filter guide rails ruby