This project is archived and is in readonly mode.
Routing when member name is update
Reported by lic (at crd) | February 9th, 2011 @ 01:19 PM
Hi I have a weird situation with routing and member
Looks like that
post 'update', :on => :member
misbehaves.
LONG STORY: I need to integrate a backend to Adobe
Flash.
Since Flash runs in a browser I don't have any PUT and DELETE.
So I used to make a POST request to ex:
/api/profiles/:id/update(.:format)
In the old Rails2 days I used to have this route
map.namespace :api do |api|
api.resources :profiles,:member => { :update => :post}
end
This generated a fine route like:
update_api_profile POST /api/profiles/:id/update(.:format) {:action=>"update", :controller=>"api/profiles"}
Now in Rails 3 I have
namespace :api do
resources :profiles do
post 'update', :on => :member
end
end
And I don't get my /api/profiles/:id/update(.:format) anymore.
If I try something like
namespace :api do
resources :profiles do
post 'update2', :on => :member
end
end
So I get the expected route /api/profiles/:id/update2(.:format)
Comments and changes to this ticket
-
lic (at crd) February 9th, 2011 @ 01:26 PM
So far I have fixed with a workaround
namespace :api do resources :profiles, :only => [:show, :create] end match '/api/profiles/:id/update(.:format)' => 'profile#update', :method => :post
but shouldn't it work as in the Rails2 API ? I mean with a proper syntax?
-
Andrew White February 9th, 2011 @ 02:33 PM
- State changed from new to wontfix
- Importance changed from to Low
Browsers don't support the PUT and DELETE http methods either so to work around this problem you can pass a form parameter which overrides the HTTP method. Just pass _method=put and the normal route will be recognised. Alternatively, if you can't change the Flash movie then just add the update route manually as you have done.
-
lic (at crd) February 10th, 2011 @ 09:01 AM
Sorry Andrew but I can't pass a _method=put. My payload is XML or JSON.
-
Andrew White February 10th, 2011 @ 09:52 AM
Okay, how about sending a custom header? You can set the X-HTTP-Method-Override header to 'PUT' and the Rack middleware will adjust the HTTP method. You'll need to provide a cross-domain policy file on the server or the request will fail: http://kb2.adobe.com/cps/403/kb403185.html
-
lic (at crd) February 10th, 2011 @ 09:59 AM
Yeps that is a possibility. We can also do this in the route
namespace :api do resources :profiles, :only => [:show, :create] match '/profiles/:id/update(.:format)' => 'profiles#update', :method => :post match '/profiles/:id/delete(.:format)' => 'profiles#destroy', :method => :delete end
And it works. My question here is why can't we make an API that is back compatible with Rails2.
-
Andrew White February 10th, 2011 @ 10:29 AM
How about this:
namespace :api do resources :profiles, :only => [:show, :create] do member do post :update, :path => 'update', :as => :update post :destroy, :path => 'destroy', :as => :destroy end end end
You need the :path and :as options to override the inbuilt defaults of blank for the action path and helper prefix.
-
lic (at crd) February 10th, 2011 @ 10:40 AM
Superb!
I didn't know that the :path option could override inbuilt defaults!
That's perfect!Thank you for helping out! I own you a beer!
-
lic (at crd) February 10th, 2011 @ 10:53 AM
Weird thing...
rake routes | grep profile api_profile_sessions POST /api/profile_sessions(.:format) {:action=>"create", :controller=>"api/profile_sessions"}
update_api_profile POST /api/profiles/:id/update(.:format) {:action=>"update", :controller=>"api/profiles"}
api_profiles POST /api/profiles(.:format) {:action=>"create", :controller=>"api/profiles"} api_profile GET /api/profiles/:id(.:format) {:action=>"show", :controller=>"api/profiles"}
So I have it and works fine.
From rspec:
Failure/Error: assert_routing("/api/profiles/PUBLICKEY/update.xml", No route matches "/api/profiles/PUBLICKEY/update.xml"
-
lic (at crd) February 10th, 2011 @ 11:24 AM
Could it be a bug in ActionDispatch::Assertions::RoutingAssertions ?
-
Andrew White February 10th, 2011 @ 12:01 PM
I don't think so - the following test works in a new app:
require 'test_helper' class RoutingTest < ActionDispatch::IntegrationTest test "API routing" do assert_routing( { :path => "/api/profiles/PUBLICKEY.xml", :method => :get }, { :controller => "api/profiles", :action => "show", :id => "PUBLICKEY", :format => "xml" } ) assert_routing( { :path => "/api/profiles.xml", :method => :post }, { :controller => "api/profiles", :action => "create", :format => "xml" } ) assert_routing( { :path => "/api/profiles/PUBLICKEY/update.xml", :method => :post }, { :controller => "api/profiles", :action => "update", :id => "PUBLICKEY", :format => "xml" } ) assert_routing( { :path => "/api/profiles/PUBLICKEY/destroy.xml", :method => :post }, { :controller => "api/profiles", :action => "destroy", :id => "PUBLICKEY", :format => "xml" } ) end end
Are you sure that the assert_routing call is being passed :method => :post? Are you using assert_routing in your spec directly?
-
lic (at crd) February 10th, 2011 @ 02:51 PM
I made it work in rspec I guess the issue was calling the wrong assertion method.
describe "Routes" do it "should route update profile from Flash" do {:post => "/api/profiles/PUBLICKEY/update.xml"}.should route_to( :controller => "api/profiles", :action => "update", :id => "PUBLICKEY", :format => "xml" ) end end
Ok I own you definitively a beer now!
Thank you for tips!
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>