Rails源码阅读(七)ActionController::Routing::Routes_用户请求在rails中的处理流程(2)
ActionController::Dispatcher把主要工作交给了ActionController::Routing::Routes.call(@env)
ActionController::Routing::Routes的代码:
Routes = RouteSet.new
原来这个常量不是个module,也不是class,是个实例
这样call方法就是RouteSet.new的call方法了
RouteSet的call代码:
def call(env) request = Request.new(env) #a new一个request真简单! app = Routing::Routes.recognize(request) #b 识别Controller 下面详细说 app.call(env).to_a #调用call,返回的结果to_a,一定是rack的标准输出了 end
Routing::Routes.recognize(request)做了什么:
def recognize(request) params = recognize_path(request.path, extract_request_environment(request)) request.path_parameters = params.with_indifferent_access #原来这个东西在这里做的!实际使用发现,一不小心,很难调试的bug就会从这里出来阿!!! "#{params[:controller].to_s.camelize}Controller".constantize end
查看返回结果,函数返回了要访问的Controller。
至此,终于接触到达了我们写的代码:XXXController处。
这样app就是某个我们自己写的Controller了,注意这是个类,不是个实例!
从app.call(env).to_a来看,每个Controller都有个call(env)方法,所以应该在父类里。看看继承结构:
XXXController < ApplicationController < ActionController::Base
果然是从super-class来的,否则自己写多麻烦:
ActionController::Base.call方法(注意这里是类方法!): class << self def call(env) # HACK: For global rescue to have access to the original request and response request = env["action_controller.rescue.request"] ||= Request.new(env) response = env["action_controller.rescue.response"] ||= Response.new process(request, response) #这里! end # ActionController::Base.process代码: # Factory for the standard create, process loop where the controller is discarded after processing. def process(request, response) #:nodoc: new.process(request, response) end end
总结:
#1 RouteSet的call方法,根据访问链接和路由配置,识别出了应该去找哪个XXXController,同时找哪个action也得到了,放入params:
Parameters: {"method"=>:get, "action"=>"follow", "controller"=>"profile"}
#2 执行XXXController.run方法
到这里,执行流程到了:ActionController::Base,即:ActionController::Base.process方法。
====结束====
=== ===
== ==
= =
| |