今天我遇到了一些奇怪的(并且非常不方便)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中的资源。有问题的路线定义如下:
...
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
....
感谢您的帮助!
答案 0 :(得分:7)
但是,即使将其定义为POST,Rails也不应该将POST请求定向到现有路径&#34; / assignments / takeover_confirmation&#34;应该采取完全不同的行动吗?
它应该。 Rails路由的匹配顺序与routes.rb
文件中定义的顺序完全相同(从上到下)。因此,如果它与某个规则匹配(并且/assignments/takeover_confirmation
匹配assignments/:id
规则),则会停止处理路由。
此行为简单有效。我想任何一种&#34; smart&#34;匹配最佳路线会导致繁琐和意外的结果。
BTW,这就是为什么全部路由曾经在路由文件的最底部定义。