论坛首页 编程语言技术论坛

Rails每周一题(二): routes

浏览 3220 次
精华帖 (0) :: 良好帖 (6) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-03-29   最后修改:2009-08-08

Rails其实很好懂,可视的源码和大量的注释,只看你有没有心去一窥究竟。今天就来看看貌似神秘的routes吧。

一个命令

首先,介绍一个rake命令。对于不了解routes定义规则的,或许看到routes.rb文件有点迷糊。不要紧,如果你想看看一个url到底对应了哪个controller以及action,就用rake routes展开所有的奥秘吧。

几多规则

routes的定义规则其实不多,让我们来一一分析下吧。不过要保持耐心。

分析routes.rb文件,首先得搞清楚,它的优先级是从上到下,谁先匹配谁先得。

1. 默认规则

 

  # Install the default routes as the lowest priority.
  # Note: These default routes make all actions in every controller accessible via GET requests. You should
  # consider removing the them or commenting them out if you're using named routes and resources.
  map.connect ':controller/:action/:id'
  map.connect ':controller/:action/:id.:format'

 

  自定义的路由规则往往需要覆盖默认的路由规则,所以,rails的routes模板把默认路由规则放在文件的最下面,并且鼓励考虑用具名路由替换它们。

2. 无名规则

  大家看到前面的map.connect,那么这个方法到底做了什么?

  # Create an unnamed route with the provided +path+ and +options+. See
  # ActionController::Routing for an introduction to routes.
  def connect(path, options = {})
     @set.add_route(path, options)
  end

 

  可以看到,connect方法为我们生成了一个无名路由规则。

  我们可以如此生成一个无名规则:

map.connect 'products/:id', :controller => 'catalog', :action => 'view'


3. 具名规则
 
  为什么要有具名规则,主要是因为rails可以为具名规则生成一些url helper。关于routes的helper,待会儿再详细描述,先来看看具名规则吧。

 

map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'


  如此,我们已经生成了一个名字叫做purchase的具名规则。
 
  看看源代码

def named_route(name, path, options = {}) #:nodoc:
    @set.add_named_route(name, path, options)
end


4. 单资源REST风格路由规则: map.resource

   我们定义这样一个规则: map.resource :account

 

   它会帮我们定义怎样的一个路由规则呢? 答案是一个遵循REST风格的路由规则,非常完美。

 

  # maps these actions in the Accounts controller:
  class AccountsController < ActionController::Base
      # GET new_account_url
       def new
         # return an HTML form for describing the new account
      end
    
      # POST account_url
      def create
        # create an account
      end
   
      # GET account_url
      def show
        # find and return the account
      end
    
     # GET edit_account_url
      def edit
        # return an HTML form for editing the account
      end
   
      # PUT account_url
      def update
        # find and update the account
      end
    
     # DELETE account_url
      def destroy
        # delete the account
      end
   end
 

    让我们用rake routes看看它为我们生成了怎样的路由。

 

    account POST                                     /account                            {:controller=>"accounts", :action=>"create"}
    formatted_account POST                 /account.:format               {:controller=>"accounts", :action=>"create"}
    new_account GET                             /account/new                    {:controller=>"accounts", :action=>"new"}
    formatted_new_account GET         /account/new.:format       {:controller=>"accounts", :action=>"new"}
    edit_account GET                             /account/edit                     {:controller=>"accounts", :action=>"edit"}
    formatted_edit_account GET          /account/edit.:format        {:controller=>"accounts", :action=>"edit"}
    GET                                                     /account                              {:controller=>"accounts", :action=>"show"}
    GET                                                     /account.:format                 {:controller=>"accounts", :action=>"show"}
    PUT                                                     /account                               {:controller=>"accounts", :action=>"update"}
    PUT                                                      /account.:format                 {:controller=>"accounts", :action=>"update"}
    DELETE                                             /account                               {:controller=>"accounts", :action=>"destroy"}
    DELETE                                             /account.:format                 {:controller=>"accounts", :action=>"destroy"}
      

5. 集合资源REST风格路由规则

 

    我们定义一个这样的规则: map.resources :messages

 

   #   map.resources :messages
 
    # will map the following actions in the corresponding controller:
      class MessagesController < ActionController::Base
       # GET messages_url
       def index
         # return all messages
       end
    
      # GET new_message_url
       def new
         # return an HTML form for describing a new message
       end
    
       # POST messages_url
       def create
         # create a new message
       end
   
     # GET message_url(:id => 1)
       def show
         # find and return a specific message
       end
   
     # GET edit_message_url(:id => 1)
       def edit
         # return an HTML form for editing a specific message
       end
   
       # PUT message_url(:id => 1)
       def update
         # find and update a specific message
       end
    
       # DELETE message_url(:id => 1)
       def destroy
         # delete a specific message
       end
     end

 

     messages GET                          /messages                                {:controller=>"messages", :action=>"index"}
     formatted_messages GET       /messages.:format                   {:controller=>"messages", :action=>"index"}
     POST                                           /messages                                {:controller=>"messages", :action=>"create"}
     POST                                           /messages.:format                   {:controller=>"messages", :action=>"create"}
     new_user GET                           /messages/new                       {:controller=>"messages", :action=>"new"}
     formatted_new_user GET       /messages/new.:format          {:controller=>"messages", :action=>"new"}
     edit_user GET                             /messages/:id/edit                  {:controller=>"messages", :action=>"edit"}
     formatted_edit_user GET        /messages/:id/edit.:format      {:controller=>"messages", :action=>"edit"}
     user GET                                      /messages/:id                          {:controller=>"messages", :action=>"show"}
     formatted_user GET                   /messages/:id.:format             {:controller=>"messages", :action=>"show"}
      PUT                                              /messages/:id                           {:controller=>"messages", :action=>"update"}
      PUT                                             /messages/:id.:format              {:controller=>"messages", :action=>"update"}
     DELETE                                        /messages/:id                          {:controller=>"messages", :action=>"destroy"}
      DELETE                                     /messages/:id.:format            {:controller=>"messages", :action=>"destroy"}



6. 嵌套规则

 

    简单嵌套规则

 

map.resources :products, :has_many => [ :comments, :sales ], :has_one => :seller
 

    用rake routes看看生成的路由规则,即可一目了然。


     一个更加复杂的嵌套规则

 

map.resources :products do |products|
    products.resources :comments
    products.resources :sales, :collection => { :recent => :get }
end
 

7. root

# You can have the root of your site routed with map.root -- just remember to delete public/index.html.
map.root :controller => 'home'  
 

     root路由用于映射根目录。

8. namespace

 

     我们还可以定义一个命名空间,如这样。

 

 

map.namespace :admin do |admin|
    # Directs /admin/products/* to Admin::ProductsController (app/controllers/admin/products_controller.rb)
   admin.resources :products
end

 

7. path_prefix, name_prefix等其他options

 

    当想让不同的method访问同一个url时,对应到不同的controller或者action,可以如是:

 

 

map.signup '/signup', :controller => 'people', :action => 'new', :conditions => {:method => :get}
map.signup '/signup', :controller => 'people', :action => 'create', :conditions => {:method => :post}
 

    还是不再赘述了,这样的option很多,在不明白的时候,不如直接看源代码吧。
 

routes helpers

 

    当我们定义了一个具名路由或者REST风格路由时,router helper会为我们生成一些帮助方法。

 

    比如当我们定义了一个这样的路由时:

 

map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'

 

     生成的helper方法有:

 

     purchase_url(:id => 1)  #  http://test.url/products/1/purchase

     purchase_path(:id => 1)  #  /products/1/purchase

     hash_for_purchase_url(:id => 1)   # {:controller=>"sessions", :action=>"new", :use_route=>:new_session, :only_path=>false}

     hash_for_purchase_path(:id => 1)  # {:controller=>"sessions", :action=>"new", :use_route=>:new_session, :only_path=>true}

 

delete & put

 

     对delete和put method,现在大多数浏览器都不能处理,所以以post方法代替,并附上:method参数。

 

 

<% form_for :message, @message, :url => message_path(@message), :html => {:method => :put} do |f| %>  
 

保持简单

 

     最后有点感触,随着项目的进行,routes会变得越来越复杂,越来越难以看懂。所以,我们要遵循保持简单,尽量使用REST风格的原则。

论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics