Walk by faith code, hack, curious

action_controller_overview

Action Controller概述[1]

通过阅读此文,能够了解在整个request过程中控制器是如何工作的.你将会了解学习到一下知识:

  1. 了解掌握控制器是如何处理请求的.
  2. 理解为什么和怎么样保存数据到会话或者 cookie
  3. 在处理请求的过程中,如何添加过滤器
  4. 使用 action controller的内建的http认证.
  5. 直接把数据展示到用户浏览器上
  6. 过滤敏感数据,不让他们显示到应用程序日志中
  7. 处理在请求过程中出现的异常

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