Ruby on Rails choosing wrong controller action -
today came across strange (and inconvenient) ruby on rails behavior persistent combing of net did not yield satisfying answer to. note: translated method , route names easier read in english, , hope did not introduce inconsistencies.
situation
environment
ruby on rails 4.2.0 executing under ruby 2.0 (also tested under ruby 2.2.0)
relevant code
consider controller these actions, among others:
class assignmentscontroller < applicationcontroller def update ... end def takeover_confirmation ... end end
routes.rb
since use lot of manually defined routes, did not use resources in routes.rb. routes in question defined follows:
... post 'assignments/:id' => 'assignments#update', as: 'assignment' post 'assignments/takeover_confirmation' => 'assignments#takeover_confirmation' ...
the relevant output of rake routes
:
assignment post /assignments/:id(.:format) assignments#update assignments_takeover_confirmation post /assignments/takeover_confirmation(.:format) assignments#takeover_confirmation
problem
when post assignments_takeover_confirmation_path
, rails routes update
method instead. server log:
started post "/assignments/takeover_confirmation" ::1 @ ... processing assignmentscontroller#update html
mitigation
if put update
route definition after takeover_confirmation
one, works intended (didn't check post update
though).
furthermore, after writing found out used wrong request type update
method in routes.rb (post instead of patch). doing in routes.rb indeed solve problem:
patch 'assignments/:id' => 'assignments#update', as: 'assignment'
however, when defining post, rails should not direct post request existing path "/assignments/takeover_confirmation" different action, should it? fear next time use 2 post routes same controller same thing again.
it seems have severe misconception of rails routing, cannot lay finger on it...
edit: solution
as katafrakt explained, above request /assignments/takeover_confirmation
matched route assignments/:id
because rails interpreted "takeover_confirmation" part string , used :id parameter. thus, expected behavior.
working example
for sake of completeness, here working (if minimalistic) route-definition should, inspired chris's comment:
resources :assignments collection post 'takeover_confirmation' end end
in example, manually created route explicitly defined. routes update, show, etc. (that defined manually @ first) implicitly defined resources: :assignments
.
corresponding excerpt rake routes
:
... takeover_confirmation_assignments post /assignments/takeover_confirmation(.:format) assignments#takeover_confirmation ... assignment /assignments/:id(.:format) assignments#show patch /assignments/:id(.:format) assignments#update put /assignments/:id(.:format) assignments#update delete /assignments/:id(.:format) assignments#destroy ....
thanks help!
however, when defining post, rails should not direct post request existing path "/assignments/takeover_confirmation" different action, should it?
it should. rails routing matched in exact same order defined in routes.rb
file (from top bottom). if matches rule (and /assignments/takeover_confirmation
matches assignments/:id
rule) stops processing routing.
this behaviour simple , efficient. imagine kind of "smart" matching best route result in cumbersome , unexpected results.
btw that's why catch-all route used defined @ bottom of routing file.
Comments
Post a Comment