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'

有什么办法吗?

4

3 回答 3

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'

将其与 in 中的方法相结合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"
于 2012-05-12T18:38:29.943 回答
2

我认为你可以做到:

link_to 'Click me', pages_path(:action)

通过重定向

match ':action' => 'pages#:action'
match '/pages/:action' => redirect(":action") # pages_path(:action) will match

这比第一个答案中建议的方法少打字,但如果有的话,似乎表达力较差。

我想您可以在视图类中覆盖 method_missing 以捕获 pages_[stuff]_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 知识或正则表达式功能,请原谅我 - 希望这至少在方向上有帮助。

于 2012-05-06T04:46:27.820 回答
0

如果你这样写你的路线,访问它的正确方法是:

link_to 'Click me', action_path(:action => 'foobar')
于 2012-04-20T07:43:46.790 回答