2012-04-20 36 views
3

我試圖寫一個通用的路線,讓我通過控制器的行動參考。如何寫在Rails 3的動態路由?

我用下面一行:

match ':action' => 'pages#:action', :as => 'action' 

假設命名的網頁控制器`foobar的」動作。我希望能寫

link_to 'Click Me', pages_foobar_path 

在視圖中。問題是,我得到的錯誤Invalid route name: ':action',當我嘗試寫這條路線。

你要知道,行

match ':action' => 'pages#:action' 

沒有:as參數完美的作品,但後來我不得不手工編寫的路徑,因爲這樣的:

link_to 'Click Me', '/pages/foobar' 

圍繞什麼辦法?

回答

0

如果你寫這樣的路線,訪問它的正確方法是:

link_to 'Click me', action_path(:action => 'foobar') 
+0

首先,謝謝你的回答。儘管如此,我正在尋找動態命名的路徑,所以我可以通過'foobar_path'來訪問它們,而不是明確指定操作。我知道我可以用個人路徑的':as'選項來做到這一點。任何方式來動態地做到這一點?謝謝! – 2012-05-06 02:40:45

+0

爲什麼你想要動態加載路徑?你知道他們是基於你的路由器配置的助手嗎?我不認爲鐵路路由器是動態的... – thiagofm 2012-05-09 01:09:36

2

我認爲你可以爲獲得儘可能遠:

通過重定向

match ':action' => 'pages#:action' 
match '/pages/:action' => redirect(":action") # pages_path(:action) will match 
link_to 'Click me', pages_path(:action) 

這比第一個答案中建議的方法輸入少,但如果有的話似乎不那麼富有表現力。

我想你可以在您的視圖類中重寫的method_missing趕上pages_ [東東] _path並生成正確的字符串,例如

def method_missing(name, *args, &block) 
    if name =~ /^pages_[a-z]*_path$/ 
    "/#{name.to_s.gsub!(/^pages_/,'').gsub!(/_path$/,'')}" 
    else 
    super 
    end 
end 

原諒我,如果我的method_missing的知識或正則表達式的能力缺乏 - 希望這是有幫助的定向至少。

+0

這絕對是正軌。所以除非有人建議更好的方法來做到這一點,否則我會在幾天內選擇這個作爲正確的答案。 – 2012-05-10 03:32:17

+0

感謝您的反饋。對於今天早上我測試它的價值,它的工作原理(一旦你將'name'賦予一個字符串,並且假設你的動作中沒有任何非alpha字符(比如「_」),但後者只是一個正則表達式調整)。留給我的唯一問題是放在哪裏。出於測試目的,我只是把它放在視圖的頂部,但這是笨重的。如果你決定這樣做,並找出一個好地方,我會好奇聽到它。 – 2012-05-10 09:49:42

5

如果動態意思是「認識我的行爲時,Rails的啓動和動態生成路線」:

這不是我會做,但它做什麼希望它沒有任何做重定向也不method_missing的運行時開銷。

config/routes.rb

controller_filenames = Dir.new("#{Rails.root}/app/controllers").entries 
controller_filenames.each do |filename| 
    # you could restrict to only the pages_controller.rb on the next line, 
    # and in that case, you could simplify even more (see next example)... 
    if filename =~ /_controller\.rb$/ 
    controller_name = filename.sub(/.rb$/, "") 
    controller_route_name = controller_name.sub(/_controller$/, "") 
    controller = controller_name.camelize.constantize.new 
    controller.action_methods.each do |action| 
     # if you don't want the controller name in your path match, just omit it... 
     match "#{controller_route_name}/#{action}" => "#{controller_route_name}##{action}", :as => "#{controller_route_name}_#{action}" 
    end 
    end 
end 

如果你只是想爲你的pages_controller.rb文件做到這一點,則:現在

controller_name = "pages_controller" 
controller_route_name = "pages" 
controller = controller_name.camelize.constantize.new 
controller.action_methods.each do |action| 
    # I've removed the controller_route_name from the match here... 
    match "#{action}" => "#{controller_route_name}##{action}", :as => "#{controller_route_name}_#{action}" 
end 

,如果動態意味着「生成的路線,每當我動態生成新的動作」

你可以重新盟友玩火。任何現有的操作都可以定義新的操作和路線。例如,我可以定義在config/routes.rb路線(但是這可能是任何現有路線):

match '/dynamic_define' => 'application#dynamic_define' 

夫婦,與在ApplicationController的方法(同樣,這可能是任何現有的動作):

def dynamic_define 
    method_name = params[:mname] 
    self.class.send(:define_method, method_name) { 
    render :text => "output from #{method_name}" 
    } 
    Rails.application.routes.disable_clear_and_finalize = true 
    Rails.application.routes.draw do 
    match "/#{method_name}" => "application##{method_name}", :as => "application_#{method_name}" 
    end 
    render :text => "dynamic_define just created a new action named #{method_name}" 
end 

在瀏覽器中,您可以訪問:

/dynamic_define?mname=my_new_dynamic_action 
# browser renders "dynamic_define just created a new action named my_new_dynamic_action" 

然後訪問:

/my_new_dynamic_action 
# browser renders "output from my_new_dynamic_action"