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:29

By changing the routes there are a whole bunch of other problems that come with that. The easiest method I have found is to do the following.

ApplicationController < ActionController::Base
  before_action :dont_allow_user_self_registration

  private

  def dont_allow_user_self_registration
    if ['devise/registrations','devise_invitable/registrations'].include?(params[:controller]) && ['new','create'].include?(params[:action])
      redirect_to root_path
    end
  end
end
查看更多
Explosion°爆炸
3楼-- · 2019-01-12 15:32

you can do this in your model

# typical devise setup in User.rb
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable

change it to:

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

notice that the symbol :registerable was removed

That's it, nothing else is required. All routes and links to registration page are magically removed too.

查看更多
干净又极端
4楼-- · 2019-01-12 15:32

I found another post similar to this one and wanted to share an answer @chrisnicola gave. In the post they were attempting to only block user signup's during production.

You could also modify the registrations controller. You can use something like this:

In "app/controllers/registrations_controller.rb"

class RegistrationsController < Devise::RegistrationsController
  def new
    flash[:info] = 'Registrations are not open.'
    redirect_to root_path
  end

  def create
    flash[:info] = 'Registrations are not open.'
    redirect_to root_path
  end
end

This will override devise's controller and use the above methods instead. They added flash messages incase that someone somehow made it to the sign_up page. You should also be able to change the redirect to any path you like.

Also in "config/routes.rb" you can add this:

devise_for :users, :controllers => { :registrations => "registrations" }

Leaving it like this will allow you to use the standard devise edit your profile. If you wish you can still override the edit profile option by including

  def update
  end

in the "app/controllers/registrations_controller.rb"

查看更多
叛逆
5楼-- · 2019-01-12 15:32

Do This in routes.rb

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

  devise_scope :user do
    get "/sign_in",  :to => "devise/sessions#new"
    get "/sign_up",  :to => "devise/registrations#new"
  end

you will get an error now while you come to sign in page, to fix it. Do this change in: app/views/devise/shared/_links.erb

<% if  request.path != "/sign_in" %>
    <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
        <%= link_to "Sign up", new_registration_path(resource_name) %><br />
    <% end -%>
<% end %>
查看更多
我想做一个坏孩纸
6楼-- · 2019-01-12 15:39

I liked @max's answer, but when trying to use it I ran into an error due to devise_mapping being nil.

I modified his solution slightly to one that seems to address the issue. It required wrapping the call to resource inside devise_scope.

devise_for :users, skip: [:registrations]

devise_scope :user do
  resource :users,
           only: [:edit, :update, :destroy],
           controller: 'devise/registrations',
           as: :user_registration do
    get 'cancel'
  end
end

Note that devise_scope expects the singular :user whereas resource expects the plural :users.

查看更多
Fickle 薄情
7楼-- · 2019-01-12 15:39

I had the same issue and I found it a bit bad practise to redirect users from the registration page. So my solution is basically is not using :registrable at all.

What I did was to create a similar page like edit user details which looked like:

<%= form_tag(update_user_update_path, method: :post) do %>  
    <br>
    <%= label_tag(:currPassword, 'Current password:') %> <%= password_field_tag(:currPassword) %> <br>
    <%= label_tag(:newPassword, 'New password:') %> <%= password_field_tag(:newPassword) %> <br>
    <%= label_tag(:newPasswordConfirm, 'Confirm new password:') %> <%= password_field_tag(:newPasswordConfirm) %> <br>
    <%= submit_tag('Update') %>
<% end %>

So this form submits into a new post end point that updates the password, which looks like:

  def update
    currPass = params['currPassword']
    newPass1 = params['newPassword']
    newPass2 = params['newPasswordConfirm']
    currentUserParams = Hash.new()
    currentUserParams[:current_password] = currPass
    currentUserParams[:password] = newPass1
    currentUserParams[:password_confirmation] = newPass2
    @result = current_user.update_with_password(currentUserParams)
  end

Later on you can use the @result in your view to tell the user whether the password is updated or not.

查看更多
登录 后发表回答