该帖已经被评为良好帖
|
|||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
作者 | 正文 | ||||||||||||||||||
发表时间:2008-03-24
经过一番试验和考虑...一,我尝试了一些思维导图工具(MindMapper,FREEMIND),但我始终没有找到一种好的方式将自己学习Rails源代码的思路表述出来,就此作罢(顺便问问,有研究思维导图的同学么?能否推荐两个自己觉得用起来比较顺手的工具)。二,不再打算整理代码运行顺序图,对不熟悉Rails源代码的同学们来说,这个图可能的确没什么帮助,甚至会把人搞晕。我现在打算从Rails源代码功能点的角度出发,根据具体功能点,结合Rails源代码进行学习,整理,总结。如果某些源代码比较复杂,牵涉类比较繁多,我仍然打算整理一个类图,从一个高的层次了解系统内部对象的关系。
首先,我们先来看一看Rails通过客户端请求,查找Controller的大致流程图
class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet def initialize(server, options) #:nodoc: @server_options = options @file_handler = WEBrick::HTTPServlet::FileHandler.new(server, options[:server_root]) # Change to the RAILS_ROOT, since Webrick::Daemon.start does a Dir::cwd("/") # OPTIONS['working_directory'] is an absolute path of the RAILS_ROOT, set in railties/lib/commands/servers/webrick.rb Dir.chdir(OPTIONS['working_directory']) if defined?(OPTIONS) && File.directory?(OPTIONS['working_directory']) super end ... end
初始化中,首先将option参数赋DispatchServlet的@server_options变量,然后生成一个FileHandler对象,这个对象的具体作用马上会提到。紧接着将Rails的工作目录设置为“working_directory”,也就是前面文章提到过的RAIL_ROOT。至此,DsipatchServlet的初始化工作完成了。WEBRick会执行此Servlet的service方法。
class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet def service(req, res) #:nodoc: unless handle_file(req, res) begin REQUEST_MUTEX.lock unless ActionController::Base.allow_concurrency unless handle_dispatch(req, res) raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." end ensure unless ActionController::Base.allow_concurrency REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked? end end end end ... end
def handle_dispatch(req, res, origin = nil) #:nodoc: data = StringIO.new Dispatcher.dispatch( CGI.new("query", create_env_table(req, origin), StringIO.new(req.body || "")), ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, data ) ... end
class Dispatcher class << self # Backward-compatible class method takes CGI-specific args. Deprecated # in favor of Dispatcher.new(output, request, response).dispatch. def dispatch(cgi = nil, session_options = CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout) new(output).dispatch_cgi(cgi, session_options) end ... end
def dispatch_cgi(cgi, session_options) if cgi ||= self.class.failsafe_response(@output, '400 Bad Request') { CGI.new } @request = CgiRequest.new(cgi, session_options) @response = CgiResponse.new(cgi) dispatch end rescue Exception => exception failsafe_rescue exception end
def dispatch run_callbacks :before handle_request rescue Exception => exception failsafe_rescue exception ensure
def run_callbacks(kind, enumerator = :each) callbacks[kind].send!(enumerator) do |callback| case callback when Proc; callback.call(self) when String, Symbol; send!(callback) when Array; callback[1].call(self) else raise ArgumentError, "Unrecognized callback #{callback.inspect}" end end end
def reload_application if Dependencies.load? Routing::Routes.reload self.unprepared = true end end
def handle_request @controller = Routing::Routes.recognize(@request) @controller.process(@request, @response).out(@output) end
def recognize(request) params = recognize_path(request.path, extract_request_environment(request)) request.path_parameters = params.with_indifferent_access "#{params[:controller].camelize}Controller".constantize end
def recognize_path(path, environment={}) routes.each do |route| result = route.recognize(path, environment) and return result end allows = HTTP_METHODS.select { |verb| routes.find { |r| r.recognize(path, :method => verb) } } if environment[:method] && !HTTP_METHODS.include?(environment[:method]) raise NotImplemented.new(*allows) elsif !allows.empty? raise MethodNotAllowed.new(*allows) else raise RoutingError, "No route matches #{path.inspect} with #{environment.inspect}" end end
def recognize(path, environment={}) write_recognition recognize path, environment end
def write_recognition # Create an if structure to extract the params from a match if it occurs. body = "params = parameter_shell.dup\n#{recognition_extraction * "\n"}\nparams" body = "if #{recognition_conditions.join(" && ")}\n#{body}\nend" # Build the method declaration and compile it method_decl = "def recognize(path, env={})\n#{body}\nend" instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})" method_decl end
def recognize(path, env={}) if (match = /\A\/posts\/?\Z/.match(path)) && conditions[:method] === env[:method] params = parameter_shell.dup params end end
def parameter_shell @parameter_shell ||= returning({}) do |shell| requirements.each do |key, requirement| shell[key] = requirement unless requirement.is_a? Regexp end end end
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|||||||||||||||||||
返回顶楼 | |||||||||||||||||||
发表时间:2008-03-26
Mindjet MindManager
|
|||||||||||||||||||
返回顶楼 | |||||||||||||||||||
发表时间:2008-03-28
您分析的很好!我想问您个问题:
关于rails的问题:就是我模型里面创建了一个回调的方法,功能是:比如:我要创建一个部落,用回调方法实现自动增加了创建者为酋长和管理员!但是我用夹具创建了一个部落,这些都没有显示出来!是怎么回事?是夹具在加载数据时饶过回调方法了吗?还是直接饶过模型,直接把数据加载到数据库里面?你有关于夹具的源代码吗?我想知道是怎么回事! |
|||||||||||||||||||
返回顶楼 | |||||||||||||||||||
发表时间:2008-03-28
你好,能否把相关源代码发给我?光看你的描述我也不清楚问题所在。短信联系
不知道下面的帖子是否对你有帮助 http://www.iteye.com/post/299671?page=3 |
|||||||||||||||||||
返回顶楼 | |||||||||||||||||||
发表时间:2008-06-28
领导!
通过你的文章学习到很多东西!搞明白了RAILS的一个大概流程!谢谢 |
|||||||||||||||||||
返回顶楼 | |||||||||||||||||||
浏览 7473 次