|
该帖已经被评为良好帖
|
|||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 作者 | 正文 | ||||||||||||||||||
|
最后更新时间:2008-06-28
经过一番试验和考虑...一,我尝试了一些思维导图工具(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
声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|||||||||||||||||||
| 返回顶楼 | |||||||||||||||||||
|
最后更新时间:2008-03-26
Mindjet MindManager
|
|||||||||||||||||||
| 返回顶楼 | |||||||||||||||||||
|
最后更新时间:2008-03-28
您分析的很好!我想问您个问题:
关于rails的问题:就是我模型里面创建了一个回调的方法,功能是:比如:我要创建一个部落,用回调方法实现自动增加了创建者为酋长和管理员!但是我用夹具创建了一个部落,这些都没有显示出来!是怎么回事?是夹具在加载数据时饶过回调方法了吗?还是直接饶过模型,直接把数据加载到数据库里面?你有关于夹具的源代码吗?我想知道是怎么回事! |
|||||||||||||||||||
| 返回顶楼 | |||||||||||||||||||
|
最后更新时间:2008-03-28
你好,能否把相关源代码发给我?光看你的描述我也不清楚问题所在。短信联系
不知道下面的帖子是否对你有帮助 http://www.javaeye.com/post/299671?page=3 |
|||||||||||||||||||
| 返回顶楼 | |||||||||||||||||||
|
最后更新时间:2008-06-28
领导!
通过你的文章学习到很多东西!搞明白了RAILS的一个大概流程!谢谢 |
|||||||||||||||||||
| 返回顶楼 | |||||||||||||||||||
浏览 3019 次






