How do I remove the Devise route to sign up?

2019-01-12 15:04发布

I'm using Devise in a Rails 3 app, but in this case, a user must be created by an existing user, who determines what permissions he/she will have.

Because of this, I want:

  • To remove the route for users to sign up.
  • To still allow users to edit their profiles (change email address and password) after they have signed up

How can I do this?

Currently, I'm effectively removing this route by placing the following before devise_for :users:

match 'users/sign_up' => redirect('/404.html')

That works, but I imagine there's a better way, right?

Update

As Benoit Garret said, the best solution in my case is to skip creating the registrations routes en masse and just create the ones I actually want.

To do that, I first ran rake routes, then used the output to re-create the ones I wanted. The end result was this:

devise_for :users, :skip => [:registrations] 
as :user do
  get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
  put 'users' => 'devise/registrations#update', :as => 'user_registration'
end

Note that:

  • I still have :registerable in my User model
  • devise/registrations handles updating email and password
  • Updating other user attributes - permissions, etc - is handled by a different controller

Actual answer:

Remove the route for the default Devise paths; i.e.:

devise_for :users, path_names: {
  sign_up: ''
}

14条回答
干净又极端
2楼-- · 2019-01-12 15:16

You could modify the devise gem itself. First, run this command to find the installed location of using:

gem which devise

Let's suppose the path is: /usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise

Then go to

/usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise/lib/devise/rails and edit routes.rb in that directory. There is a method called def devise_registration(mapping, controllers) which you can modify to get rid of the new action. You can also completely remove the mappings for devise_registration

查看更多
相关推荐>>
3楼-- · 2019-01-12 15:21

I tried to do this as well, but a thread on the devise google group dissuaded me from searching for a really clean solution.

I'll quote José Valim (the Devise maintainer) :

There isn't a straight-forward option. You can either provide a patch or use :skip => :registerable and add only the routes you want.

The original question was :

Is there any good way to remove a specific route (the delete route) from Rails?

查看更多
男人必须洒脱
4楼-- · 2019-01-12 15:22

I had similar issue tried to remove devise_invitable paths for create and new :

before:

 devise_for :users

rake routes

accept_user_invitation GET    /users/invitation/accept(.:format)           devise/invitations#edit
       user_invitation POST   /users/invitation(.:format)                  devise/invitations#create
   new_user_invitation GET    /users/invitation/new(.:format)              devise/invitations#new
                       PUT    /users/invitation(.:format)                  devise/invitations#update

after

devise_for :users , :skip => 'invitation'
devise_scope :user do
  get "/users/invitation/accept", :to => "devise/invitations#edit",   :as => 'accept_user_invitation'
  put "/users/invitation",        :to => "devise/invitations#update", :as => nil
end

rake routes

accept_user_invitation GET    /users/invitation/accept(.:format)                 devise/invitations#edit
                       PUT    /users/invitation(.:format)                        devise/invitations#update

note 1 devise scope https://github.com/plataformatec/devise#configuring-routes

note 2 I'm applying it on devise_invitable but it will work with any devise *able feature

Important note: see that devise_scope is on user not users ? that's correct, watch out for this ! It can cause lot of pain giving you this problem:

Started GET "/users/invitation/accept?invitation_token=xxxxxxx" for 127.0.0.1 
Processing by Devise::InvitationsController#edit as HTML
  Parameters: {"invitation_token"=>"6Fy5CgFHtjWfjsCyr3hG"}
 [Devise] Could not find devise mapping for path "/users/invitation/accept?  invitation_token=6Fy5CgFHtjWfjsCyr3hG".
This may happen for two reasons:

1) You forgot to wrap your route inside the scope block. For example:

  devise_scope :user do
     match "/some/route" => "some_devise_controller"
  end

 2) You are testing a Devise controller bypassing the router.
   If so, you can explicitly tell Devise which mapping to use:

    @request.env["devise.mapping"] = Devise.mappings[:user]
查看更多
劫难
5楼-- · 2019-01-12 15:22

Here's the slightly different route I went. It makes it so you don't have to override the devise/shared/_links.html.erb view.

In app/models/user.rb:

devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable

In config/routes.rb:

devise_for :users
devise_scope :user do
  put 'users' => 'devise/registrations#update', as: 'user_registration'
  get 'users/edit' => 'devise/registrations#edit', as: 'edit_user_registration'
  delete 'users' => 'devise/registrations#destroy', as: 'registration'
end

Before:

$ rake routes | grep devise
           new_user_session GET    /users/sign_in(.:format)                    devise/sessions#new
               user_session POST   /users/sign_in(.:format)                    devise/sessions#create
       destroy_user_session DELETE /users/sign_out(.:format)                   devise/sessions#destroy
              user_password POST   /users/password(.:format)                   devise/passwords#create
          new_user_password GET    /users/password/new(.:format)               devise/passwords#new
         edit_user_password GET    /users/password/edit(.:format)              devise/passwords#edit
                            PATCH  /users/password(.:format)                   devise/passwords#update
                            PUT    /users/password(.:format)                   devise/passwords#update
   cancel_user_registration GET    /users/cancel(.:format)                     devise/registrations#cancel
          user_registration POST   /users(.:format)                            devise/registrations#create
      new_user_registration GET    /users/sign_up(.:format)                    devise/registrations#new
     edit_user_registration GET    /users/edit(.:format)                       devise/registrations#edit
                            PATCH  /users(.:format)                            devise/registrations#update
                            PUT    /users(.:format)                            devise/registrations#update
                            DELETE /users(.:format)                            devise/registrations#destroy

After:

$ rake routes | grep devise
           new_user_session GET    /users/sign_in(.:format)                    devise/sessions#new
               user_session POST   /users/sign_in(.:format)                    devise/sessions#create
       destroy_user_session DELETE /users/sign_out(.:format)                   devise/sessions#destroy
              user_password POST   /users/password(.:format)                   devise/passwords#create
          new_user_password GET    /users/password/new(.:format)               devise/passwords#new
         edit_user_password GET    /users/password/edit(.:format)              devise/passwords#edit
                            PATCH  /users/password(.:format)                   devise/passwords#update
                            PUT    /users/password(.:format)                   devise/passwords#update
          user_registration PUT    /users(.:format)                            devise/registrations#update
     edit_user_registration GET    /users/edit(.:format)                       devise/registrations#edit
               registration DELETE /users(.:format)                            devise/registrations#destroy
查看更多
我想做一个坏孩纸
6楼-- · 2019-01-12 15:23

You can override the "devise_scope" by placing it before the "devise_for".

devise_scope :user do
  get "/users/sign_up",  :to => "sites#index"
end

devise_for :users

Not sure if this is the best way but its my solution currently, as it just redirects back to the sign in page.

查看更多
地球回转人心会变
7楼-- · 2019-01-12 15:24

I've found this to work well without messing with routes or adding application controller methods. My approach is to override the devise method. Add this to app/controllers/devise/registrations_controller.rb I've omitted the other methods for brevity.

class Devise::RegistrationsController < DeviseController
  ...
  # GET /resource/sign_up
  def new
    redirect_to root_path
  end
  ....
end

Also to remove illusion that this path is still reachable from other views you might also want to remove this code from app/views/devise/shared/_links.erb

<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
  <%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end -%>
查看更多
登录 后发表回答