0

除了 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的方法showfoo和的路由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

注意这两种情况下路径的区别:虽然 helper 路径和 controller#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 栏中手动输入匹配的 URL ( reso/foo) 时,它按预期工作。但是,尝试foo_reso从应用程序中打开路由会导致No route matches [GET] "/foo_reso". foo_reso_pathfoo_reso_url导致相同的错误。

到底是什么问题?肯定不是 Rails 中的错误?

添加于编辑,2013-07-22:

为了使用例更清晰,想法是当用户按下页面上的“重置”按钮时,reset会调用控制器的方法,该方法会清除页面的输入和输出。我一直在通过将实际标识符更改resetfoo. (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 %>">

表格包括 partial _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_pathTop::ResoController该值是变量中赋予表单的值@reset_path,即"foo_reso"

请记住,当我这样定义时,所有这些工作都foo_reso很好routes.rb

get 'foo_reso' => 'top/reso#foo'

另请记住,在赋值语句中替换foo_resofoo_reso_path或替换没有任何区别。foo_reso_urlResoController

我使用的地方在foo_reso控制器和视图中,所以这应该不是问题。

4

3 回答 3

1

如描述中所述,这里是“用法”。

# 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。检查是否可以直接访问路由是好的,因此检查路由助手的使用是否正确也很重要

于 2013-07-23T12:23:37.327 回答
0

简短的回答:Rails 中没有自动的方法来做到这一点。

原因是 RESTul URL 基本上依赖于 format /controller/action。这意味着如果您的控制器ResoController有 3 个方法showfoobar,则正确的 restful 实现将产生 URL:

/reso
/reso/foo
/reso/bar

Rails 可以帮助您实现这一目标,并且解决方案正在members您的路线中使用,正是您在问题中描述的方式。

使用诸如/foo_resoor之类的 URL /bar_reso- 换句话说/action_controller不是 Rails 标准,Rails 的基本理念是“约定优于配置”。所以如果你真的需要那些你必须手动声明它们

于 2013-07-22T11:18:38.827 回答
0

好的,我发现了问题。在挖掘一个看似神秘的错误后,通常会出现这种情况,解决方案非常简单。我的reso_controller.rb是:

类 Top::ResoController < Top::ResoSuperController

# 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

我现在不觉得很傻。很抱歉浪费时间。

于 2013-07-22T12:10:44.237 回答