该帖已经被评为良好帖
|
|||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
作者 | 正文 | ||||||||||
发表时间:2008-03-21
在《Routing的载入》中,我大致介绍了一下Rails中最简单的route是如何加载的。这篇文章,我将来讲一讲Rails系统中更为复杂的named route和与RESTful相关的resource是如何被加载的。为了不重复太多的笔墨,这篇文章将在前文的基础上进行,如果发现单独看此文时,有少许云里雾里,建议先看一看我的前篇文章:Ruby On Rails-2.0.2源代码分析(2)-Routing的载入
首先,named route的载入全部发生在routing.rb中。其实named route一点也不比普通的route高深些什么,Rails内部最终也是将named route解析为一个普通的route保存在RouseSet类的routes数组中(还记得这家伙么?最好牢牢记住他,因为,他还会在后续文章中继续登台发挥重要作用),之所以我称他进化,是因为named route既然提供了name,在Rails内部,将会生成一系列的helper方法,当我们在controller或者view中使用link_to,redirect_to等方法时,不需要指定相应的controller和action,从而简化我们的代码,不用多了,先来看一看我们所熟悉的routes.rb ActionController::Routing::Routes.draw do |map| map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase' ... end
def method_missing(route_name, *args, &proc) #:nodoc: super unless args.length >= 1 && proc.nil? @set.add_named_route(route_name, *args) end
def add_named_route(name, path, options = {}) # TODO - is options EVER used? name = options[:name_prefix] + name.to_s if options[:name_prefix] named_routes[name.to_sym] = add_route(path, options) end
def add(name, route) routes[name.to_sym] = route define_named_route_methods(name, route) end def get(name) routes[name.to_sym] end alias []= add alias [] get
def define_named_route_methods(name, route) {:url => {:only_path => false}, :path => {:only_path => true}}.each do |kind, opts| hash = route.defaults.merge(:use_route => name).merge(opts) define_hash_access route, name, kind, hash define_url_helper route, name, kind, hash end end
def define_hash_access(route, name, kind, options) selector = hash_access_name(name, kind) @module.module_eval <<-end_eval # We use module_eval to avoid leaks def #{selector}(options = nil) options ? #{options.inspect}.merge(options) : #{options.inspect} end protected :#{selector} end_eval helpers << selector end def define_url_helper(route, name, kind, options) selector = url_helper_name(name, kind) # The segment keys used for positional paramters hash_access_method = hash_access_name(name, kind) @module.module_eval <<-end_eval # We use module_eval to avoid leaks def #{selector}(*args) #{generate_optimisation_block(route, kind)} opts = if args.empty? || Hash === args.first args.first || {} else options = args.last.is_a?(Hash) ? args.pop : {} args = args.zip(#{route.segment_keys.inspect}).inject({}) do |h, (v, k)| h[k] = v h end options.merge(args) end url_for(#{hash_access_method}(opts)) end protected :#{selector} end_eval helpers << selector end
当然,光把RESTful和resource扯到一起似乎相当狭义,在Rails中,ActionController::Resources抽象了REST中的Resource,这里,我不谈REST的相关概念,网上资料一大坨。我们就来看看Rails中是如何通过Resource来轻松,简便的完成RESTful应用的吧。 resources.rb 源代码路径:/actionpack-2.0.2/lib/action_controller/resources.rb map.resources :products
从这个角度来想,你可以把resource想成是众多相关named
route的一个马甲。我们先从宏观的角度来看一看Rails是如何完成Resource到route转换的。 ActionController::Routing::Routes.draw do |map| map.resources :products ... end
def resources(*entities, &block) options = entities.extract_options! entities.each { |entity| map_resource(entity, options.dup, &block) } end
def map_resource(entities, options = {}, &block) resource = Resource.new(entities, options) with_options :controller => resource.controller do |map| map_collection_actions(map, resource) map_default_collection_actions(map, resource) map_new_actions(map, resource) map_member_actions(map, resource) map_associations(resource, options) if block_given? with_options(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], &block) end end end
def map_member_actions(map, resource) resource.member_methods.each do |method, actions| actions.each do |action| action_options = action_options_for(action, resource, method) map.named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action}", action_options) map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action}.:format",action_options) end end show_action_options = action_options_for("show", resource) map.named_route("#{resource.name_prefix}#{resource.singular}", resource.member_path, show_action_options) map.named_route("formatted_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", show_action_options) update_action_options = action_options_for("update", resource) map.connect(resource.member_path, update_action_options) map.connect("#{resource.member_path}.:format", update_action_options) destroy_action_options = action_options_for("destroy", resource) map.connect(resource.member_path, destroy_action_options) map.connect("#{resource.member_path}.:format", destroy_action_options) end
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|||||||||||
返回顶楼 | |||||||||||
浏览 5858 次