Rails 3 routing: is there a way to remove a route from Rails.application.routes?

Here is what Jose Valim (the author of devise) has to say on the subject.

Up vote 7 down vote favorite 3 share g+ share fb share tw.

Devise_for creates the usual routes, including a DELETE route. Because of a nasty bug on our site (related to IE 8 not behaving itself! ), we just want to remove the DELETE route altogether.

We have no need of it. Unfortunately, devise_for doesn't support an :except or :only option (from what I can tell). I'm wondering how I can remove a route from Rails.application.

Routes? Either in the draw block, or afterward? Thanks!

EDIT: some details of the bug referred to above we were issuing a DELETE request to a custom UJS controller action in the controller action we were removing what we wanted to, then doing a 302 redirect. This was a bad idea, and we have since corrected it by returning some JSON instead. Some clients, upon receiving the 302 would issue a new DELETE request to the redirect, which routes to a Devise delete route!

Thereby inadvertantly deleting the person! Yikes. We were assuming this would be a GET.

Bad assumption. This bug has been fixed, but I would like to remove the route nonetheless. EDIT 2: so I started a bounty on the question, I really want to know if its possible to party directly on the RouteSet in Rails.

EDIT 3: Here is what I did in the end, which was suggested by the bounty-winner in his quote from Jose´ Valim: In config/routes. Rb, I added this ABOVE the devise_for call which sets up the rest of my 'people' routes: delete '/person', :to => 'people#destroy' Then in my existing people_controller. Rb I added a no-op method: def destroy render :nothing => true end This is the simplest thing that could possibly work in this situation, or is it?

I'm still a little irked that there isn't a simple way to just remove the route from the RouteSet. Also, the delete route still exists for the devise controller, but it won't get called because rails looks for the first match in config\routes. Rb and returns it.

Ok, thanks for the help everyone! Ruby-on-rails ruby-on-rails-3 devise routes link|improve this question edited Aug 17 '11 at 15:05 asked Aug 8 '11 at 18:34ipd1,491416.

2 Nice questions. And would be nice to know what that IE8 bug is! – Zabba Aug 8 '11 at 18:41 I added an edit with the story of our bug.

Not sure the bug is exclusive to IE8, see this answer on 302s: stackoverflow.com/questions/4764297/…. – ipd Aug 8 '11 at 19:09 For posterity I've appended another solution to my answer. – dwhalen Aug 17 '11 at 16:19.

Here is what Jose Valim (the author of devise) has to say on the subject: There is no way to remove routes individually. Or you use :skip to remove all and draw the ones you need manually or you overwrite this routes by defining a route to the same path first in your config/ routes. Rb So the short answer to your question is no, you can't delete that one route.

You can of course try doing things like patching the devise_for method, but that would be a somewhat involved undertaking (a day or several worth of effort). I'd just use the :skip option, then implement the routes you do want for that controller and leave off the one that you don't.

I'm awarding you the bounty for the quote from José Valim, thanks! – ipd Aug 17 '11 at 14:56.

Yes, kinda. You can completely overwrite devise controllers used and write your own (inheriting Devise's if needed). This wiki page can serve as guideline.

Edit Why I have said kinda :) Overriding sessions using: devise_for :users, :controllers => { :sessions => 'custom_devise/sessions'}, :skip => :sessions do get 'sign_in' => 'custom_devise/sessions#new', :as => :new_user_session post 'sign_in' => 'custom_devise/sessions#create', :as => :user_session end will give you only two routes :get, :post, but not :destroy new_user_session GET /sign_in(.:format) {:controller=>"custom_devise/sessions", :action=>"new"} user_session POST /sign_in(.:format) {:controller=>"custom_devise/sessions", :action=>"create"} So, effectively, you skip destroy/delete route. Now in controller you can go: class SessionsController "devise/sessions#new" post "sign_in", :to => "devise/sessions#create" ... end Gives: sign_in GET /sign_in(.:format) {:controller=>"devise/sessions", :action=>"new"} POST /sign_in(.:format) {:controller=>"devise/sessions", :action=>"create"} Third Edit Also, you could overwrite part of Devise in charge of creating these routes, (only to be used in applications that will have no devise "destroy" route whatsoever), by creating an initializer: module ActionDispatch::Routing extend ActionDispatch::Routing class Mapper protected def devise_session(mapping, controllers) #:nodoc: resource :session, :only => , :controller => controllers:sessions, :path => "" do get :new, :path => mapping. Path_names:sign_in, :as => "new" post :create, :path => mapping.

Path_names:sign_in end end def devise_registration(mapping, controllers) #:nodoc: path_names = { :new => mapping. Path_names:sign_up, :cancel => mapping. Path_names:cancel } resource :registration, :only => :new, :create, :edit, :update, :path => mapping.

Path_names:registration, :path_names => path_names, :controller => controllers:registrations do get :cancel end end end end Note that this fix removes all destroy routes used in Devise (there are only two in "sessions" and "registrations") and is a fix only for this specific case. In addition You could also add :except option to routes. In order to do it, you must add devise_for method (copy it from original and modify to suit your wishes) to Mapper class so it sends :except member of options to above-mentioned (in code) private methods.. Then you should modify those to add routes based on conditions.

Fastest, dirty way, would be to add @scope:except = options:except and then to modify private methods so that except hash (if you decide to have fine grained route control like: :except => {:sessions => :destroy}, thus making :skip obsolete) or array (if you want to remove this specific action from all routes, like: :except => :destroy) is checked before adding route. Anyway, there are plenty ways to achieve what you need. It's up to you to pick the one you think is best suited.

1 I know I can redirect a route to a new controller, but i'd like to remove the route altogether. – ipd Aug 8 '11 at 20:39 Please see edit. I hope that is what you want.

You can't just remove route but you can override devise routes this way leaving it out. – Krule Aug 8 '11 at 21:03 And I just remembered, there is a simpler way: edit2 – Krule Aug 8 '11 at 21:23 I have 13 person routes that I would have to specify, just to remove one! I suppose I could just specify a match for the one route and then reroute it to no_op controller action.

But thats a horrible hack, seems like I should be able to specify one route to remove from the RouteSet object. – ipd Aug 8 '11 at 22:13 Well, other than forking devise, making necessary changes, and pushing back, or asking for this feature hoping someone will write it, this is, as far as I know, the only way. – Krule Aug 8 '11 at 22:30.

Actually devise_for does support :skip and :only, for example (docs): devise_for :user, :skip => :registration This will skip all the registration controller's routes, rather than one specifically. You could then implement the routes you need. This seems cleaner than removing the route after the fact.

UPDATE: Another possible solution is to use Rails' advanced constraints feature to block the unwanted route completely: # config/routes. Rb constraints lambda {|req| req. Url =~ /users/ && req.

Delete? False : true} do devise_for :users end Here is a post on using lambdas for route constraints. The request object is explained here.

This might be the simplest solution.

Yes, kinda. You can completely overwrite devise controllers used and write your own (inheriting Devise's if needed). This wiki page can serve as guideline.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions