2012-04-20 38 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"