除了Rails默认定义的资源之外,还想将自定义路由定义为某些资源。 为此,我的routes.rb
文件的相关部分如下所示:
resource :top, only: [:show]
scope module: :top do
resource :reso, only: [:show]
end
get 'foo_reso' => 'top/reso#foo'
get 'bar_reso' => 'top/reso#bar'
如您所见,我只想要路由到 ResoController
的方法show
、foo
和 bar
。 这有效,正如rake routes
给出的那样:
reso GET /reso(.:format) top/reso#show
foo_reso GET /foo_reso(.:format) top/reso#foo
bar_reso GET /bar_reso(.:format) top/reso#bar
这是有效的:单击应用程序中的链接,将您带到路由foo_reso
确实会导致呼叫ResoController#foo
,以及关联视图的后续显示。
但是,我认为路由定义只是有点丑陋,而不是定义路由显式,而是希望 Rails 通过告诉它资源有两个额外的 REST 方法自动生成它们,foo
和 bar
(同时仍然通过 only:
参数限制标准方法(。
我遵循了这个答案中的建议,并将routes.rb
改为:
resource :top, only: [:show]
scope module: :top do
resource :reso, only: [:show] do
member do
get :foo
get :bar
end
end
end
现在,rake routes
给出:
reso GET /reso(.:format) top/reso#show
foo_reso GET /reso/foo(.:format) top/reso#foo
bar_reso GET /reso/bar(.:format) top/reso#bar
请注意两种情况下路径之间的差异:虽然帮助程序路径和控制器#action相同,但路径已从/foo_reso(.:format)
更改为/reso/foo(.:format)
。
(我在config/initializers/inflections.rb
中将所有资源名称定义为不可数,所以我不会自动复数名称,因为在我的应用程序中,每个控制器都与特定屏幕相关联,而不是与模型相关联,因此复数不适合图片。在这个应用程序中,REST 方法实际上更像是函数调用,而不是对资源的操作,这就是为什么我需要与标准不同的集合。
现在,单击应用程序中foo_reso
的链接会导致 Rails 路由错误页面,其中显示:
No route matches [GET] "/foo_reso"
除了使用我原来的解决方案之外,关于我可以做些什么来解决这个问题的任何想法?
添加编辑, 2013-07-12:
正如我在下面的评论中指出的那样,根据 rake routes
的输出,帮助程序路由foo_reso
与我要调用的控制器和方法匹配,top/reso#foo
,当我手动输入匹配的 URL ( reso/foo
( 到 URL 栏中时,它会按预期工作。 但是,尝试从应用程序内打开路由foo_reso
会导致No route matches [GET] "/foo_reso"
。 foo_reso_path
和foo_reso_url
会导致相同的错误。
问题到底是什么? 肯定不是 Rails 中的错误吗?
2013-07-22 编辑添加:
为了使用例更清晰一些,这个想法是当用户按下页面上的"重置"按钮时,将调用控制器的reset
方法,该方法清除页面的输入和输出。我一直通过将实际标识符reset
更改为foo
来抽象问题。(reso
和其他几个标识符也是"混淆"的结果。 为了保持一致性,我将继续使用相同的翻译,但是当您记住foo
实际上是reset
时,下面的代码应该更清晰。(bar
是别的,但没关系,因为路由问题是相同的。
为了回答Thong Kuah和John Hinnegan的问题,这就是我使用foo_reso_path
的方式。 文件reso_controller
的相关部分:
class Top::ResoController < Top::ResoSuperController
# GET /reso
def show
...
@reset_path = "foo_reso"
...
end # show
# GET /foo_reso
def foo
perform_foo_action
redirect_to reso_path
end
...
end
文件app/views/top/reso/show.html.erb
的相关部分:
<%= render partial: "top/resosuper_inputs", locals: { the_form_path: reso_path } %>
...
<input type="hidden" id="reset_path" name="reset_path" value="<%= @reset_path %>">
该表格包括部分_resosuper_inputs.html.erb
,其相关部分是:
<!-- For using the "Reset" button. -->
<%= javascript_include_tag "my_reset_form.js" %>
<%= simple_form_for :filtering_criteria, url: the_form_path, method: :get do |f| %>
... inputs elided ...
<%= f.button :submit, value: "Search" %>
<%= f.button :submit, type: 'button', value: "Reset"), id: 'reset_button' %>
<% end %>
resosuper
是两种不同资源的超类,但我认为这对案件没有任何影响。无论如何,这是Javascript文件app/assets/javascripts/my_reset_form.js
:
$(document).ready(function() {
/* Hang functionality on the "Reset" button. */
$('#reset_button').click(function () {
var reset_path = $('#reset_path').val();
window.open(reset_path, "_self")
});
})
它在jQuery中,正如注释所说,使"重置"按钮打开其值已存储在隐藏输入变量中的路径,ID reset_path
。 该值是变量@reset_path
中Top::ResoController
赋予形式的值,即"foo_reso"
。
请记住,当我在routes.rb
中定义foo_reso
时,所有这些都工作正常,如下所示:
get 'foo_reso' => 'top/reso#foo'
另请记住,在 ResoController
的赋值语句中用 foo_reso_path
或foo_reso_url
替换foo_reso
没有区别。
我使用foo_reso
的位置在控制器和视图中,所以这应该不是问题。
如描述中所述,这里是"用法"。
# GET /reso
def show
...
@reset_path = "foo_reso"
...
end # show
但是,上述所做的只是将@reset_path
实例变量设置为文字字符串"foo_reso"(巧合的是与旧路由匹配(
海报真正想要的是:
@reset_path = foo_reso_path
这将生成正确的路径/reso/foo
到实例变量@reset_path
旁注:海报在这里做了所有正确的事情来调试路由问题。大多数时候,您可以信任rake routes
.检查是否可以直接访问路由是好的,因此检查路由助手的使用是否正确也至关重要
简短回答:在 Rails 中没有自动的方法可以做到这一点。
原因是 RESTul URL 基本上依赖于格式/controller/action
。这意味着如果你的控制器ResoController
有 3 个方法show
、foo
和 bar
,正确的 restful 实现将产生 URL:
/reso
/reso/foo
/reso/bar
Rails 可以帮助您实现这一目标,解决方案是在路线中使用members
,与您在问题中描述的方式完全相同。
使用诸如/foo_reso
或/bar_reso
之类的URL-换句话说/action_controller
不是Rails的标准,而Rails的基本理念是"约定优于配置"。因此,如果您真的需要它们,则必须手动声明它们
好的,我发现了问题所在。在挖掘一个看似神秘的错误后,情况往往如此,解决方案非常简单。我reso_controller.rb
是:
类 顶部::Reso控制器 <顶部::Reso超级控制器>
# GET /reso
def show
...
@reset_path = "foo_reso"
...
end # show
我用这个替换了分配行:
@reset_path = foo_reso_path
foo_reso_path
周围没有引号. 现在,"重置"按钮按预期工作。
总之,以下方法不起作用:
@reset_path = "foo_reso"
@reset_path = "foo_reso_path"
@reset_path = "foo_reso_url"
@reset_path = foo_reso
以下内容确实有效:
@reset_path = foo_reso_path
@reset_path = foo_reso_url
我现在不觉得傻吗。很抱歉浪费时间。