Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

_method=put ignored for xhr and xml requests

#2289

In previous versions of Rails you could do something like this:

curl -H "Accept: text/xml"

   -H "Content-type: application/xml"
    d "_method=put" 
    -X POST http://localhost.com:3000/posts/1

Rails would recognize the POST request as a put because of the _method=put param and your restful routes would work correctly.

In 2.3.2 this no longer works for xml requests. It does for html. So

curl d "_method=put" -X POST http://localhost.com:3000/posts/1

will hit the update action.

But if you add hte Accpet: "text/xml" header then will interpret the request as a post request and map the request to the create method.

This is a problem with Ajax forms that want to use restful routes but can only issue GET and POST requests.

Reported by Greg DeVore · March 18th, 2009 @ 06:11 PM

State: stale
Milestone: 3.x
Assigned to: nobody
Importance: none

Activity

  1. Greg DeVore
    Greg DeVore

    Did some more investigating on this. If an xml request is made a _method=put in the params Rack::MethodOverride is never hit. You have to add an HTTP_X_HTTP_METHOD_OVERRIDE header.

    Is there is a reason why xml requests won't look at the _method param?

    March 18th, 2009 @ 07:50 PM

  2. Greg DeVore
    Greg DeVore
    • Tag set to method, middleware, request, xml

    OK - I was going down the wrong path on this one. The real problem is that in previous versions of rails you could have from post data and pass _method=put as a query param. The routing would recognize it as a put request.

    In 2.3, if you don't put the _method=put into the form data, but into the query then it won't be recognized as a put request. I have made a small change to the Rack::MethodOverride module that fixes this but I am not sure if there are any negative consequences for including it.

    March 19th, 2009 @ 01:29 AM

  3. Brian Lopez
    Brian Lopez

    I have this same issue with posting JSON as the request body format. From what I could find, it seems that the check for the METHOD_OVERRIDE_PARAM_KEY (which is set to "_method") is being done on req.POST which is empty in my JSON request. Changing that req.POST check to use req.env['action_controller.request.request_parameters'] fixes the problem for me. I'm hesitant to submit this as a patch because I'm assuming it breaks the general nature of middleware that may want to avoid ActionController completely. But maybe this Rack::MethodOverride middleware comes so late in the chain it doesn't matter?

    Anyway, this is around line 15 of methodoverride.rb in the bundled Rack 1.0 in Rails 2.3.2.

    March 23rd, 2009 @ 07:25 PM

  4. Brian Lopez
    Brian Lopez

    After thinking about it a little more, doing this change in Rack is a bad idea. I think the actual fixable issue is that ActionController::ParamsParser sets env["action_controller.request.request_parameters"] to the parsed params. But Rack sets up it's Request#POST hash based on env['rack.input'] (I think).

    It seems like two things might have to change... If ActionController::ParamsParser were to set the value of env["rack.request.form_hash"] instead of env["action_controller.request.request_parameters"], AND Rack were to check if env["rack.request.form_hash"] was already from other middleware in the chain?

    March 23rd, 2009 @ 07:34 PM

  5. Brian Lopez
    Brian Lopez

    Forgot to mention, setting HTTP_X_HTTP_METHOD_OVERRIDE worked fine without any of my above mentioned changes as well. I think I like this better anyway.

    March 23rd, 2009 @ 07:36 PM

  6. Szymon Nowak
    Szymon Nowak

    Do you still have this problem?

    Recently after upgrading to Rails 2.3.2 suddenly in place editing plugin that we use stopped working giving "only get, put and delete method allowed" when requesting JSON using PUT method.

    Thanks to you guys we managed to fix it by swapping Rack::MethodOverride with the patched version provided here (see http://guides.rubyonrails.org/ra... for swapping middlewares).

    But later it turned out that this problem was caused by facebooker gem that we were using - it was inserting its own Rack middleware into the stack that caused this problem - updating it to 1.0.25 fixed this problem and we could remove our patched version of Rack::MethodOverride middleware.

    April 2nd, 2009 @ 08:38 PM

  7. Rich
    Rich

    I'm hitting up against this too, however, this just started happening when I created a metal app.

    http://gist.github.com/115937

    At first I thought it might be related to the paths I've defined in my metal app, but even if I just declare a bare bones metal app(i.e., class MyMetalApp;end;) all restful update actions are broken and I get this error:

    Only get, put, and delete requests are allowed.

    This seems to be the only ticket related to this issue. Not sure if I should file a new one.

    May 22nd, 2009 @ 06:14 AM

  8. Rich
    Rich

    Forgot to mention this is happening for standard text/html requests.

    May 22nd, 2009 @ 06:15 AM

  9. Marcus Wyatt
    Marcus Wyatt

    I've also stumbled into this problem when we upgraded our product to Rails version 2.3.2. It's a worry, because our app utilizes XML extensively.

    June 4th, 2009 @ 05:16 AM

  10. Andy Watts
    Andy Watts

    This is also an issue when adding PUT links in active_scaffold

    July 22nd, 2009 @ 09:41 PM

  11. Sean Grove
    Sean Grove

    I'm having the same problem here with XHR requests. I'm working on developing the gwt-on-rails plugin, but we don't seem to be able to PUT anything as it's simply being ignored via either XHR JSON or XML requests.

    August 13th, 2009 @ 12:00 PM

  12. joost baaij
    joost baaij

    Fwiw, the actual request header to send is called X-Http-Method-Override. So in curl, to simulate a JSON PUT request that would be:

    curl -H "X-Http-Method-Override: put" -H "Content-Type: application/json" -d "{blah@example.com"}}"">user www.example.com/users/username.json

    Took me a few hours of research. Including _method in the JSON hash had no effect whatsoever though.

    December 19th, 2009 @ 08:16 PM

  13. Jeremy Kemper
    Jeremy Kemper
    • Milestone changed from 2.x to 3.x

    May 4th, 2010 @ 06:48 PM

  14. Neeraj Singh
    Neeraj Singh
    • Importance changed from to

    In rails3 edge all the following three requests worked just fine for me.

    $ curl -X POST -d "user[name]=John" -d "_method=PUT" http://localhost:3000/users/1
    $ curl -X POST -d "user[name]=John2" "Content-Type: text/xml" -d "_method=PUT" http://localhost:3000/users/1
    $ curl -X POST -d "user[name]=John3" "Content-Type: application/json" -d "_method=PUT" http://localhost:3000/users/1
    

    June 28th, 2010 @ 06:12 PM

  15. Mike (at coverallcrew)
    Mike (at coverallcrew)

    Neeraj,

    Those work for html requests, but if you try a JSON request _method=PUT param will fail. Although, sending the header HTTP_X_HTTP_METHOD_OVERRIDE=put does work for xhr.

    July 6th, 2010 @ 11:21 PM

  16. Andrew White
    Andrew White

    Mike, how are you doing the request? Only POST requests will have their method overridden. Also the _put variable needs to be in the form data and not the query string. This is the simple Rack middleware that does the overriding:

    module Rack
      class MethodOverride
        HTTP_METHODS = %w(GET HEAD PUT POST DELETE OPTIONS)
    
        METHOD_OVERRIDE_PARAM_KEY = "_method".freeze
        HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE".freeze
    
        def initialize(app)
          @app = app
        end
    
        def call(env)
          if env["REQUEST_METHOD"] == "POST"
            req = Request.new(env)
            method = req.POST[METHOD_OVERRIDE_PARAM_KEY] ||
              env[HTTP_METHOD_OVERRIDE_HEADER]
            method = method.to_s.upcase
            if HTTP_METHODS.include?(method)
              env["rack.methodoverride.original_method"] = env["REQUEST_METHOD"]
              env["REQUEST_METHOD"] = method
            end
          end
    
          @app.call(env)
        end
      end
    end
    

    As you can see it's not a complicated bit of code so the way you build your JSON request is probably triggering the error. I think previously in the pre-Rack days the _method could either be in the query or the form data and that tends to catch people out.

    July 7th, 2010 @ 04:56 AM

  17. Andrew White
    Andrew White
    • State changed from new to needs-more-info

    August 20th, 2010 @ 06:43 AM

  18. Santiago Pastorino
    Santiago Pastorino
    • State changed from needs-more-info to open

    This issue has been automatically marked as stale because it has not been commented on for at least three months.

    The resources of the Rails core team are limited, and so we are asking for your help. If you can still reproduce this error on the 3-0-stable branch or on master, please reply with all of the information you have about it and add "[state:open]" to your comment. This will reopen the ticket for review. Likewise, if you feel that this is a very important feature for Rails to include, please reply with your explanation so we can consider it.

    Thank you for all your contributions, and we hope you will understand this step to focus our efforts where they are most helpful.

    February 2nd, 2011 @ 04:59 PM

  19. Santiago Pastorino
    Santiago Pastorino
    • State changed from open to stale

    February 2nd, 2011 @ 04:59 PM

  20. Michael Latta
    Michael Latta

    This is still an issue with 3.0.6 and query parameters with method=put for ajax requests. I just ran into this today with porting 2.x code to the 3.x version of a site. using jQuery.post to a URL that includes ?mthod=put&... does not get treated as a PUT request, but as a POST.

    April 25th, 2011 @ 07:33 PM

  21. Michael Latta
    Michael Latta

    By changing the call from $.post to $.ajax with type 'PUT' this seems to resolve the issue.

    April 25th, 2011 @ 08:02 PM