This project is archived and is in readonly mode.
Rails 2.3 JSON "put" request routing is broken
-
David Burger
I'm having the same problem. Code that performed a POST with _method="PUT" using Prototype Ajax.Request worked fine under 2.2.2 and now does not route to the update action in Rails 2.3.2.
-
jonas (at stixy)
Yeah, me too. Is anyone working on this? Or, have anyone found a solution?
-
Andriy Tyurnikov
Did you call rake rails:update after switching to 2.3.2? Please post your error message
-
Joseph Chen
Yes rake rails:update was run.
The error is:
"Only get, put, and delete requests are allowed."
The stack:
/Users/jc/.multiruby/install/1.8.7-p72/lib/ruby/gems/1.8/gems/actionpack-2.3.2/lib /action_controller/routing/recognition_optimisation.rb:64:in
recognize_path' /Users/jc/.multiruby/install/1.8.7-p72/lib/ruby/gems/1.8/gems/actionpack-2.3.2/lib/action_controller /routing/route_set.rb:437:inrecognize' /Users/jc/.multiruby/install/1.8.7-p72/lib/ruby/gems/1.8/gems/actionpack-2.3.2/lib/action_controller /routing/route_set.rb:432:incall' -
Ryan Bigg
Please show the code you are using that is generating the form / whatever that is PUT'ing.
-
Joseph Chen
The post is being done in Ajax, and we happen to be using the ExtJS library for the Ajax request. As I have mentioned, you can reproduce this simply by doing a POST, passing the form variable "_method" = "put", and setting content-type to "application/json".
var postData = {
'_method': 'put', 'test': { 'name':'test name' }, 'authenticity_token':window._token }Ext.lib.Ajax.setDefaultPostHeader(false);
Ext.lib.Ajax.initHeader("Content-Type", "application/json; charset=utf-8"); Ext.Ajax.request({ url: url, method: 'POST', params: Ext.util.JSON.encode(postData), }); -
Joseph Chen
I've stepped through the ActionController routing code and seem to have a fix for the problem.
I've edited the gems/actionpack-2.3.2/lib/action_controller/routing/route_set.rb, line 483.
The problem was that the previous code set the method to request.method and didn't take into the account the 'method' parameter. So I simply change the code to check if the method is a post and the 'method' parameter is provided, then the method should be set to whatever the value for method is.
def extract_request_environment(request)
method = request.method if method == :post if request.env['action_controller.request.request_parameters'].include?('_method') method = request.env['action_controller.request.request_parameters']['_method'].to_sym end end { :method => method } endI've attached the route_set.rb file.
I'm not sure if this is the best place to be setting the method type, but it seems to fix the problem.
-
Joseph Chen
I found a bug with the fix I posted above. It turns out that the key 'action_controller.request.request_parameters' is not always present. So we need to check if it exists.
I also extracted the fix out into a file that can be added as config/initializers/rails_action_controller_fix.rb. So the fix simply overrides the default method with the fix.
In addition, I added a check for the Rails version so that the fix is only applied when using Rails 2.3.2.
if RAILS_GEM_VERSION == '2.3.2' module ActionController
module Routing class RouteSet def extract_request_environment(request) method = request.method if method == :post params_key = 'action_controller.request.request_parameters' if request && request.env && request.env.include?(params_key) && request.env[params_key].include?('_method') method = request.env[params_key]['_method'].to_sym end end { :method => method } end end endend end
I'd appreciate any suggestions if anyone has a better way to implement this fix.
-
Zyclops
Client side this is what i have to make the request:
@@@javascript
Ext.onReady(function() {
Ext.Ajax.request({url: '/publications/index', method: 'POST', jsonData: {whatever: {hello: 'test'}}}); });
-
Joseph Chen
Zyclops, you are missing the '_method': 'put' in your jsonData. Your request should look like:
url: '/publications/index', method: 'POST', jsonData: { 'whatever': {'hello': 'test'}, '_method': 'put' } -
Seth Ladd
For the record, we ran into this bug as well.
-
Laurence A. Lee
IIRC, Rails 2.3 is now Rack Based. This may be the same Rack bug I ran into months ago. Here's the quick-fix:
http://github.com/lalee/rack/commit/1f3fa756192cd5a0524f6fa136c71d9...
Hope this helps.
-
seamusabshere
This may help:
module ActionController
class ParamsParser private def parse_formatted_parameters(env) env['rack.input'].rewind # <-- add this request = Request.new(env) -
lbayes (at patternpark)
We are experiencing this issue also.
-
Cameron Westland
It seems like this could be because the ParamsParser rack middleware is converting application/json requests to a single json object… I'm having the problem too.
-
Uwe Mesecke
- Tag changed from 2.3.2, json, put, request, rest, routing to 2.3.2, 2.3.5, json, patch, put, request, rest, routing
This issue is still present in rails 2.3.5. The fix by Joseph Chen (adding the file to config/initializers) fixed this bug for me. Is there any change that a fix for this problem can be added to the next release? The problem is easily reproducable, a fix is present and reported to be working by several people. Are there any other obstacles I am missing?
-
Rizwan Reza
- Milestone changed from 2.x to 2.3.6
-
eggie5
i'm seeing this bug too, Joseph Chen's fix works.
-
edraut
I see this in rails 2.3.5, and Joseph Chen's fix did not work, because the Rack::Request object does not have #action_controller. However, this is available:
Rack::Request#params
So I modified Joseph Chen's fix thusly:
module ActionController module Routing class RouteSet def extract_request_environment(request) method = request.method if method == :post params_key = 'action_controller.request.request_parameters' Rails.logger.info("REQUEST::::::::: #{request.env['QUERY_STRING']}") if request && request.params && request.params.include?('_method') method = request.params['_method'].to_sym end if request && request.env && request.env.include?(params_key) && request.env[params_key].include?('_method') method = request.env[params_key]['_method'].to_sym end end Rails.logger.info("METHOD::::::::: #{method}") { :method => method } end end end endI left the other bit in there in case there's some ambiguity I don't know about where #action_controller may be available in some other case. Can anyone confirm for me that this is necessary?
In any event this works for me now.
-
Neeraj
Given that rails3 is just around the corner how about using -H "X-Http-Method-Override: put" as an extra option to get around this issue.
this works
curl -X POST -d "user[name]=John" -d "_method=PUT" http://localhost:3000/users/1
this does not work
curl -H 'Accept: application/xml' -H 'Content-type: application/xml' http://localhost:3000/users/1.xml -d 'John' -X POST
this works
curl -H "X-Http-Method-Override: put" -H 'Accept: application/xml' -H 'Content-type: application/xml' http://localhost:3000/users/1.xml -d 'John' -X POST -
Rizwan Reza
- Tag changed from 2.3.2, 2.3.5, json, patch, put, request, rest, routing to 2.3.2, 2.3.5, bugmash, json, patch, put, request, rest, routing
-
nicolas_o
- Importance changed from to
I have this problem too, using rails 2.3.8. The fix works. Any better solution in sight ?
-
Dru Jensen
What about setting the method to "PUT" instead of "POST"?
Ext.onReady(function() {
Ext.Ajax.request({
url: '/publications/index',
method: 'PUT',
jsonData: {whatever: {hello: 'test'}}
}); }); -
nicolas_o
The issue is gone with rails 3. I don't need the monkey-patch anymore.
