action_controller_overview
Action Controller概述[1]
通过阅读此文,能够了解在整个request过程中控制器是如何工作的.你将会了解学习到一下知识:
- 了解掌握控制器是如何处理请求的.
- 理解为什么和怎么样保存数据到会话或者 cookie
- 在处理请求的过程中,如何添加过滤器
- 使用 action controller的内建的http认证.
- 直接把数据展示到用户浏览器上
- 过滤敏感数据,不让他们显示到应用程序日志中
- 处理在请求过程中出现的异常
Chapters
- What Does a Controller Do?
- Methods and Actions
- Parameters
- Hash and Array Parameters
- JSON/XML parameters
- Routing Parameters
- default_url_options
- Session
- Accessing the Session
- The Flash
- Cookies
- Rendering xml and json data
- Filters
- After Filters and Around Filters
- Other Ways to Use Filters
- Request Forgery Protection
- The Request and Response Objects
- The request Object
- The response Object
- HTTP Authentications
- HTTP Basic Authentication
- HTTP Digest Authentication
- Streaming and File Downloads
- Sending Files
- RESTful Downloads
- Parameter Filtering
- Rescue
- The Default 500 and 404 Templates
- rescue_from
- Force HTTPS protocol
控制器干什么?
Action Controller 在 mvc
的架构中充当的是 c
的角色. 在路由觉得那个控制器来处理这个请求之后, 这个控制器就会开始负责处理这个请求,然后然会一个正确的 响应给用户.幸运的是, 控制器做了为你做了很多的工作,通过约定来让使用它尽可能简单.
对于一般常见的 RESTful 应用, 控制器接收请求, 然后从 model
中获取或者保存数据, 之后利用视图来html输出.如果你的控制器想做点其他的事情,也没有问题,而这也是控制器擅长的.
控制器可看做是对象和视图之前的中间人,它能够让冷冰冰的数据在视图上以一定的方式展现出来.同样能够把用户在页面上输入的数据以一定方式保存.
方法和动作
一个控制器就是一个继承自 ApplicationController
的ruby 类,它有方法,和其他类一样,当应用程序收到一个请求之后,路由会指派具体哪个控制器的那个动作来处理. 之后Rails 创建一个控制器的实例, 然后执行对应的那个方法.
class ClientsController < ApplicationController
def new
end
end
举例子,如果一个用户想要访问/clients/new
来添加一个用户, Rails就会创建一个 ClientsController
然后执行new
方法,注意上面new方法虽然是一个空的.但是rails会默认创建一个 new.html.erb
视图,除非该action指定了其他的. 这个 new 方法, 像下面的代码, 在视图里你可以访问 @client
这个对象:
def new
@client = Client.new
end
在 布局和渲染教程中 会详细说道.
ApplicationController 继承自 ActionController::Base
它定义了很多的帮助方法,本文中会涉及到一些,但是如果有兴趣你可以通过阅读 API的文档或者源代码 来了解学习.
在控制器中只有公共的方法可以做动作来被访问, 这个是一个较好地实践,降低方法的可见性.
参数
你可能会去访问用户输入的数据或者其他参数在控制器里,一般在应用程序中有2类参数,第一种是通过 url
传来的, 我们习惯性称之为 query string(查询字符串),一般就是在URL中以 ?
连接, 其后的就是参数,另外一种就是通过 post
表单提交过来的.rails 对于这两种不会区别对待的,他们都是会在 params
这个hash 对象中访问到.
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
else
@clients = Client.unactivated
end
end
# 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.new(params[:client])
if @client.save
redirect_to @client
else
# This line overrides the default rendering behavior, which
# would have been to render the "create" view.
render :action => "new"
end
end
end
字典和数据参数
这个 params
字典不仅限于一维,它可以包含数组或者嵌套字典, 看看这个例子:
GET /clients?ids[]=1&ids[]=2&ids[]=3
因为在实际的URL中不允许 [
和 ]
, 所以encode之后最终的URL 是类似这样的:“/clients?ids%5b%5d=1&ids%5b%5d=2&ids%5b%5d=3”
但是通常不会去注意这些的,因为浏览器和rails会帮助你搞定这些的.在解析之后的参数中, 对应的 ids
就是一个数组:
[:ids] => [“1”, “2”, “3”]
记住一点,在这里从url过来的所有参数都是字符串,rails不会试图转换他们的类型. 看看下面的例子,在form表单中,数据的名称中包含方括号:
<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" />
</form>
当这个表单被调教之后,解析之后的参数就是
params[:client]
=>
{
"name" => “Acme”,
“phone” => “12345”,
“address” => {"postcode" => “12345”, “city” => “Carrot City”}
}
值得一提的是, 这个params
字典是一个来自 Active support的 HashWithIndifferentAccess
实例, 它能够使用户通过symbol或者字符串作为键来访问字典值.
Json/xml 参数
如果你是在写web service服务,你可能觉得传一个json 或者 xml比较舒服,Rails会自动得把这个类型参数转换为 params
字典.你可以完全和上面的访问一样正常访问参数值. 所有,例如:
{ “company”: { “name”: “acme”, “address”: “123 Carrot Street” } }
你会得到一个重要的params:
params[:company] as { :name => “acme”, “address” => “123 Carrot Street” }.
如果你在配置文件中打开了 config.wrap_parameters
在初始化的时候, 或者在控制器里直接调用 wrap_parameters
方法,你可以安全的忽略掉 json/xml 的根节点. 参数将会根据控制器的名字默认的被克隆封装params中. 所以上面的参数会成为这样的:
{ “name”: “acme”, “address”: “123 Carrot Street” }
假设我们发送数据到 CompaniesController, 它会被封装到对应的 :company
键上:
{ :name => “acme”, :address => “123 Carrot Street”, :company => { :name => “acme”, :address => “123 Carrot Street” }}
路由参数
这个 params
字典总是会包括 :controller 和 :action 2个键.但是你应该用 方法 controller_name
和 action_name
来获取他们的值.还有其他的一些值例如 :id
也可以获取到. 有这么一个例子,我们要列表显示用户,通过他们的状态区分,我们可以通过路由添加一个参数 :status
来实现:
match ‘/clients/:status’ => ‘clients#index’, :foo => “bar”
这样,当一个用户访问 /clients/active
, 参数 params[:status] 就会被赋值为 active
, 而且, params[:foo] 会被赋值为 bar
, 就好像它通过query string方式一样.同样, params[:action]的值就是 index
了.
default_url_options
可以通过调用这个方法 default_url_options
来给url生成设置一些默认的参数,例如一个方法必须返回翻一个字典,包含一个默认的值.
class ApplicationController < ActionController::Base
def default_url_options
{:locale => I18n.locale}
end
end
这些选项会被在开始生成url的时候使用, 所以他很有可能被重写如果之后调用 url_for
方法.
如果你像上面例子里那样在ApplicationController中定义 default_url_options
, 当生成url的时候就会被调用. 同样可以定义在特定的控制器中. 只对哪里的url生成起作用.
Written with StackEdit.