Ruby on Rails选择错误的控制器动作

时间:2015-03-16 21:06:20

标签: ruby-on-rails-4 rails-routing

今天我遇到了一些奇怪的(并且非常不方便)Ruby on Rails行为,即使持续梳理网络也没有产生令人满意的答案。 注意:我将方法和路由名称翻译为更容易用英语阅读,并希望我没有引入任何不一致。

情况

环境

Ruby on Rails 4.2.0在Ruby 2.0下执行(也在Ruby 2.2.0下测试)

相关代码

考虑使用这些操作的控制器,其中包括:

class AssignmentsController < ApplicationController
  def update
    ...
  end

  def takeover_confirmation
    ...
  end
end

的routes.rb

由于我使用了大量手动定义的路由,因此使用routes.rb中的资源。有问题的路线定义如下:

...
post 'assignments/:id' => 'assignments#update', as: 'assignment'
post 'assignments/takeover_confirmation' => 'assignments#takeover_confirmation'
...

rake routes的相关输出:

assignment POST  /assignments/:id(.:format)  assignments#update
assignments_takeover_confirmation  POST  /assignments/takeover_confirmation(.:format) assignments#takeover_confirmation

问题

当我对assignments_takeover_confirmation_path进行POST时,rails会将其路由到update方法。服务器日志:

Started POST "/assignments/takeover_confirmation" for ::1 at ...
Processing by AssignmentsController#update as HTML

缓解

如果我将update路由定义放在 takeover_confirmation之后,它会按预期工作(虽然没有检查到update的POST )。

此外,写完所有这些之后我发现我在routes.rb(POST而不是PATCH)中使用了错误的请求类型update方法。在routes.rb中这样做确实解决了我的问题:

patch 'assignments/:id' => 'assignments#update', as: 'assignment'

但是,即使将其定义为POST,Rails也不应该将POST请求定向到现有路径&#34; / assignments / takeover_confirmation&#34;应该采取完全不同的行动吗? 我担心下次我为同一个控制器使用两个POST路由时,它会再次做同样的事情。

看起来我对Rails路由有一种严重的误解,但是不能指责它......

编辑:解决方案

正如katafrakt解释的那样,上面对/assignments/takeover_confirmation的请求与路由assignments/:id匹配,因为Rails解释了&#34; takeover_confirmation&#34; part作为字符串并用于:id参数。因此,这是完全预期的行为。

工作示例

为了完整起见,这里有一个工作(如果是简约的)路线定义,应该受到Chris的评论的启发:

  resources :assignments do
    collection do
      post 'takeover_confirmation'
    end
  end

在此示例中,仅显式定义了手动创建的路径。更新,显示等的路由(我最初手动定义)现在由resources: :assignments隐式定义。

rake routes的相应摘录:

...
takeover_confirmation_assignments  POST  /assignments/takeover_confirmation(.:format) assignments#takeover_confirmation
...
assignment GET    /assignments/:id(.:format)  assignments#show
           PATCH  /assignments/:id(.:format)  assignments#update
           PUT    /assignments/:id(.:format)  assignments#update
           DELETE /assignments/:id(.:format)  assignments#destroy
....

感谢您的帮助!

1 个答案:

答案 0 :(得分:7)

  

但是,即使将其定义为POST,Rails也不应该将POST请求定向到现有路径&#34; / assignments / takeover_confirmation&#34;应该采取完全不同的行动吗?

它应该。 Rails路由的匹配顺序与routes.rb文件中定义的顺序完全相同(从上到下)。因此,如果它与某个规则匹配(并且/assignments/takeover_confirmation匹配assignments/:id规则),则会停止处理路由。

此行为简单有效。我想任何一种&#34; smart&#34;匹配最佳路线会导致繁琐和意外的结果。

BTW,这就是为什么全部路由曾经在路由文件的最底部定义。