I'm a Ruby on Rails / jQuery web developer. Follow me at @sikachu

My Devise custom routes

December 13th, 2010 Posted in My Idea, Programming, Ruby, Ruby on Rails

Since the release of Rails 3, I’ve been using Devise as my authentication gem. While it delivers everything I need, its default route doesn’t look really good when I have only one authentication scope, such as User. The default route when you’re using devise_for :users will look like this:

         new_user_session GET    /users/sign_in(.:format)          {:action=>"new", :controller=>"devise/sessions"}
             user_session POST   /users/sign_in(.:format)          {:action=>"create", :controller=>"devise/sessions"}
     destroy_user_session GET    /users/sign_out(.:format)         {:action=>"destroy", :controller=>"devise/sessions"}
            user_password POST   /users/password(.:format)         {:action=>"create", :controller=>"devise/passwords"}
        new_user_password GET    /users/password/new(.:format)     {:action=>"new", :controller=>"devise/passwords"}
       edit_user_password GET    /users/password/edit(.:format)    {:action=>"edit", :controller=>"devise/passwords"}
                          PUT    /users/password(.:format)         {:action=>"update", :controller=>"devise/passwords"}
 cancel_user_registration GET    /users/cancel(.:format)           {:action=>"cancel", :controller=>"devise/registrations"}
        user_registration POST   /users(.:format)                  {:action=>"create", :controller=>"devise/registrations"}
    new_user_registration GET    /users/sign_up(.:format)          {:action=>"new", :controller=>"devise/registrations"}
   edit_user_registration GET    /users/edit(.:format)             {:action=>"edit", :controller=>"devise/registrations"}
                          PUT    /users(.:format)                  {:action=>"update", :controller=>"devise/registrations"}
                          DELETE /users(.:format)                  {:action=>"destroy", :controller=>"devise/registrations"}
        user_confirmation POST   /users/confirmation(.:format)     {:action=>"create", :controller=>"devise/confirmations"}
    new_user_confirmation GET    /users/confirmation/new(.:format) {:action=>"new", :controller=>"devise/confirmations"}
                          GET    /users/confirmation(.:format)     {:action=>"show", :controller=>"devise/confirmations"}

As you can see, all of the routes are defined under /users path. So, I’ve modified my devise route block to this:

devise_for :users, :skip => [:registrations, :sessions] do
  # devise/registrations
  get 'signup' => 'devise/registrations#new', :as => :new_user_registration
  post 'signup' => 'devise/registrations#create', :as => :user_registration
  get 'users/cancel' => 'devise/registrations#cancel', :as => :cancel_user_registration
  get 'users/edit' => 'devise/registrations#edit', :as => :edit_user_registration
  put 'users' => 'devise/registrations#update'
  delete 'users/cancel' => 'devise/registrations#destroy'
 
  # devise/sessions
  get 'signin' => 'devise/sessions#new', :as => :new_user_session
  post 'signin' => 'devise/sessions#create', :as => :user_session
  get 'signout' => 'devise/sessions#destroy', :as => :destroy_user_session
end

Which will yield these routes:

    new_user_registration GET    /signup(.:format)                 {:action=>"new", :controller=>"devise/registrations"}
        user_registration POST   /signup(.:format)                 {:action=>"create", :controller=>"devise/registrations"}
 cancel_user_registration GET    /users/cancel(.:format)           {:controller=>"devise/registrations", :action=>"cancel"}
   edit_user_registration GET    /users/edit(.:format)             {:controller=>"devise/registrations", :action=>"edit"}
                    users PUT    /users(.:format)                  {:action=>"update", :controller=>"devise/registrations"}
             users_cancel DELETE /users/cancel(.:format)           {:controller=>"devise/registrations", :action=>"destroy"}
         new_user_session GET    /signin(.:format)                 {:action=>"new", :controller=>"devise/sessions"}
             user_session POST   /signin(.:format)                 {:action=>"create", :controller=>"devise/sessions"}
     destroy_user_session GET    /signout(.:format)                {:action=>"destroy", :controller=>"devise/sessions"}
            user_password POST   /users/password(.:format)         {:action=>"create", :controller=>"devise/passwords"}
        new_user_password GET    /users/password/new(.:format)     {:action=>"new", :controller=>"devise/passwords"}
       edit_user_password GET    /users/password/edit(.:format)    {:action=>"edit", :controller=>"devise/passwords"}
                          PUT    /users/password(.:format)         {:action=>"update", :controller=>"devise/passwords"}
        user_confirmation POST   /users/confirmation(.:format)     {:action=>"create", :controller=>"devise/confirmations"}
    new_user_confirmation GET    /users/confirmation/new(.:format) {:action=>"new", :controller=>"devise/confirmations"}
                          GET    /users/confirmation(.:format)     {:action=>"show", :controller=>"devise/confirmations"}

I think my new routes is much better. For example, I think user would prefer a path to sign in page to be /signin than /users/sign_in, as it more memorable.

I hope this post would inspire you more about customize Devise’s routes to fit your need.

  • http://chesmart.in ches

    Nice. I use something very similar, and also do `devise_for :users, :path => ‘accounts’` because I feel like RESTful paths like /accounts/edit are nicer from a user perspective, but I still want to be referencing a ‘User’ model in my code.

  • Pingback: Tweets that mention My Devise custom routes | Sikachu!'s Blog -- Topsy.com()

  • http://sikachu.com/ Prem Sichanugrist

    Yes, I agree. Or maybe `account` for better yet? … If we look it in RESTful way, I feel like it should be singular instead.

  • http://chesmart.in ches

    Indeed, hadn’t even thought about making it a singular resource but it really should be.

  • Jean-philippe Lannoy

    Nice, exactly what I’m looking for. There is a little error at the last line, this is delete ‘signout’ not get ‘signout’

  • http://sikachu.com/ Prem Sichanugrist

    I’m using `get ‘signout’` so user can actually go to `/signout` to signing out, without having to do a POST.