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

Viewed 10935

devise_for creates routes including a DELETE route, which we want to remove, and devise_for doesn't support an :except or :only option.

How can I remove a route from Rails.application.routes? Either in the draw block, or afterward?


Here are details of a bug, which was the reason we needed to remove the route.

  • 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.


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

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.

4 Answers

I found a simple solution with Devise 4.2.0 and Rails 5.0.1. I think this will work with Rails 4, and I'm uncertain about older versions of Devise.

Create an initializer overriding the devise_* route helpers. Examples methods are devise_session, devise_password, devise_confirmation, devise_unlock, and devise_registration. Check out the source.

Ensure the initializer is loaded after the Devise initializer by giving the filename a larger alphanumeric value.

For example, Devise creates a :confirmation route with the :new, :create, and :show actions. I only want the :create action.

# config/initializers/devise_harden.rb
module ActionDispatch::Routing
  class Mapper

    # Override devise's confirmation route setup, as we want to limit it to :create
    def devise_confirmation(mapping, controllers)
      resource :confirmation, only: [:create],
               path: mapping.path_names[:confirmation], controller: controllers[:confirmations]
    end
  end
end

Now POST /auth/confirmation is the only route setup for confirmation.

Related