Ruby On Rails-2.0.2源代码分析(3)-resource

  • RESTful的化身----resource

当然,光把RESTful和resource扯到一起似乎相当狭义,在Rails中,ActionController::Resources抽象了REST中的Resource,这里,我不谈REST的相关概念,网上资料一大坨。我们就来看看Rails中是如何通过Resource来轻松,简便的完成RESTful应用的吧。

resources.rb

源代码路径:/actionpack-2.0.2/lib/action_controller/resources.rb
首先,我们也不需要将resource看得多么的高深,你可以把他理解为,当你在routes.rb中定义如下的resource的时候:

map.resources :products
Rails会自动为我们生成众多的named route,这些route通过http verb和相应的controller中的action对应起来,当然了,众多的helper方法也随即产生。如下表所示:

Named Route Helpers
product
product_url, hash_for_product_url,
product_path, hash_for_product_path
new_product
new_product_url, hash_for_new_product_url,
new_product_path, hash_for_new_product_path
edit_product
edit_product_url, hash_for_edit_product_url,
edit_product_path, hash_for_edit_product_path
... ...

从这个角度来想,你可以把resource想成是众多相关named route的一个马甲。

整个流程比较的直观,Rails通过resource按部就班的完成各种route的生成,接下来我们看一看核心代码是如何完成这些功能的。首先,还是在routes.rb中,可能会定义如下的resource:

Ruby代码
  1. ActionController::Routing::Routes.drawdo|map|
  2. map.resources:products
  3. ...
  4. end


resources方法定义在ActionController::Resources这个module中,然后通过mixin进入到Mapper类的。那我们首先来看一看这个方法:

Ruby代码
  1. defresources(*entities,&block)
  2. options=entities.extract_options!
  3. entities.each{|entity|map_resource(entity,options.dup,&block)}
  4. end


很简单,将entities和options从参数中分离开来,然后针对每一个entity执行map_resource操作。我们继续进行,看看map_resource方法的真面目:

Ruby代码
  1. defmap_resource(entities,options={},&block)
  2. resource=Resource.new(entities,options)
  3. with_options:controller=>resource.controllerdo|map|
  4. map_collection_actions(map,resource)
  5. map_default_collection_actions(map,resource)
  6. map_new_actions(map,resource)
  7. map_member_actions(map,resource)
  8. map_associations(resource,options)
  9. ifblock_given?
  10. with_options(:path_prefix=>resource.nesting_path_prefix,:name_prefix=>resource.nesting_name_prefix,:namespace=>options[:namespace],&block)
  11. end
  12. end
  13. end


有了entity和options,还等什么呢?马上生成我们的Resource对象,Resource对象封装了和此resource相关的collection method,member method,new method,path prefix,name prefix,单/复数表示,还有option。生成这个Resource对象无非就是将此对象的相应属性从options中解析出来,保存起来,代码比较简单,这里就不再贴出。
现在,Resource对象有了,从上面代码我们就可以看出来,接下来,就该处理和此resource相关named route了。具体的处理逻辑都类似,这里将map_member_actions(map, resource)拿出来作为示意,感兴趣的同学们可以自己查看相关的源代码。

Ruby代码
  1. defmap_member_actions(map,resource)
  2. resource.member_methods.eachdo|method,actions|
  3. actions.eachdo|action|
  4. action_options=action_options_for(action,resource,method)
  5. map.named_route("#{action}_#{resource.name_prefix}#{resource.singular}","#{resource.member_path}#{resource.action_separator}#{action}",action_options)
  6. map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}","#{resource.member_path}#{resource.action_separator}#{action}.:format",action_options)
  7. end
  8. end
  9. show_action_options=action_options_for("show",resource)
  10. map.named_route("#{resource.name_prefix}#{resource.singular}",resource.member_path,show_action_options)
  11. map.named_route("formatted_#{resource.name_prefix}#{resource.singular}","#{resource.member_path}.:format",show_action_options)
  12. update_action_options=action_options_for("update",resource)
  13. map.connect(resource.member_path,update_action_options)
  14. map.connect("#{resource.member_path}.:format",update_action_options)
  15. destroy_action_options=action_options_for("destroy",resource)
  16. map.connect(resource.member_path,destroy_action_options)
  17. map.connect("#{resource.member_path}.:format",destroy_action_options)
  18. end


这里,我们可以很直观的看到,Rails为resource的member相关方法生成了众多的route,我们可以看到Controller中熟悉的show,update,destroy action。是的,在这里,Rails就为url到controller的action生成了相应的route。

本文转自:http://woody-420420.javaeye.com/blog/174352

你可能感兴趣的:(REST,Blog,Ruby,Rails)