Ruby On Rails-2.0.2原始碼分析(3)-resource

來源:互聯網
上載者:User
  • 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.draw do |map|   
  2.   
  3.   map.resources :products  
  4.   ...   
  5. end  
ActionController::Routing::Routes.draw do |map|  map.resources :products  ...end

  resources方法定義在ActionController::Resources這個module中,然後通過mixin進入到Mapper類的。那我們首先來看一看這個方法:

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

  很簡單,將entities和options從參數中分離開來,然後針對每一個entity執行map_resource操作。我們繼續進行,看看map_resource方法的真面目:

 

Ruby代碼
  1. def map_resource(entities, options = {}, &block)   
  2.   resource = Resource.new(entities, options)   
  3.   
  4.   with_options :controller => resource.controller do |map|   
  5.     map_collection_actions(map, resource)   
  6.     map_default_collection_actions(map, resource)   
  7.     map_new_actions(map, resource)   
  8.     map_member_actions(map, resource)   
  9.   
  10.     map_associations(resource, options)   
  11.   
  12.     if block_given?   
  13.       with_options(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], &block)   
  14.     end  
  15.   end  
  16. 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  endend

  有了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. def map_member_actions(map, resource)   
  2.   resource.member_methods.each do |method, actions|   
  3.     actions.each do |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.   
  10.   show_action_options = action_options_for("show", resource)   
  11.   map.named_route("#{resource.name_prefix}#{resource.singular}", resource.member_path, show_action_options)   
  12.   map.named_route("formatted_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", show_action_options)   
  13.   
  14.   update_action_options = action_options_for("update", resource)   
  15.   map.connect(resource.member_path, update_action_options)   
  16.   map.connect("#{resource.member_path}.:format", update_action_options)   
  17.   
  18.   destroy_action_options = action_options_for("destroy", resource)   
  19.   map.connect(resource.member_path, destroy_action_options)   
  20.   map.connect("#{resource.member_path}.:format", destroy_action_options)   
  21. 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

  這裡,我們可以很直觀的看到,Rails為resource的member相關方法產生了眾多的route,我們可以看到Controller中熟悉的show,update,destroy action。是的,在這裡,Rails就為url到controller的action產生了相應的route。

 

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.