Jay-Ar Polidario
Jay-Ar Polidario

Reputation: 6603

PUT or PATCH `_method` param not working or not being respected in rails-api

TLDR:

Using rails --api, expected rails to route as PUT method from POST and params[:_method]='put', but is routing as POST

Given:

Consider the following:

config/routes.rb:

resources :sessions, do
  put 'authenticate', on: :collection
end

some client HTML file:

<form action='http://localhost:3000/sessions/authenticate' method='post'>
  <input type='hidden' name='_method' value='put'>
  ...
</form>

...upon form submit:

rails server output:

Started POST "/sessions/authenticate" for ::1 at 2018-03-07 11:20:21 +0000
No route matches [POST] "/sessions/authenticate" excluded from capture: DSN not set

ActionController::RoutingError (No route matches [POST] "/sessions/authenticate"):
  actionpack (4.2.8) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
  actionpack (4.2.8) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  ...

Inspecting Chrome -> Developer Tools -> Network tab -> [REQUEST], the payload is correct as shown below:

General
Request URL:http://localhost:3000/sessions/authenticate
...

FormData
_method:put
...

Troubleshooting

Any help would be appreciated.

Upvotes: 4

Views: 2001

Answers (1)

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230461

Handling of _method hidden fields is done by a piece of rack middleware.

http://guides.rubyonrails.org/configuring.html#configuring-middleware

Rack::MethodOverride allows the method to be overridden if params[:_method] is set. This is the middleware which supports the PATCH, PUT, and DELETE HTTP method types.

I'm guessing you don't have that in api mode. Add it and the request should be routed correctly.

Bonus track

I didn't know this myself (or forgot a long time ago). Here's how I found out.

  1. Go to https://github.com/rails/rails and try to search that repo for :_method (as this is likely how rails would address the field). After two minutes realize that github doesn't search the exact term.
  2. Clone rails repo locally (5 mins)
  3. Grep the local codebase (0.5 seconds)

    sergio@soviet-russia ‹ master › : ~/projects/github/rails
    [0] % ag ":_method"
    guides/source/rails_on_rack.md
    238:* Allows the method to be overridden if `params[:_method]` is set. This is the middleware which supports the PUT and DELETE HTTP method types.
    
    guides/source/configuring.md
    235:* `Rack::MethodOverride` allows the method to be overridden if `params[:_method]` is set. This is the middleware which supports the PATCH, PUT, and DELETE HTTP method types.
    

Total time taken: ~7 minutes. Rails itself actually didn't contain actual relevant code, but it had the docs. I got lucky. :)

Upvotes: 6

Related Questions