如何删除Devise路线进行注册?


147

我在Rails 3应用程序中使用Devise,但是在这种情况下,必须由现有用户创建用户,该用户确定他/她将拥有哪些权限。

因此,我想要:

  • 删除路线的用户注册
  • 为了还允许用户编辑自己的个人资料(变更电子邮件地址和密码),双方已经签署了

我怎样才能做到这一点?

目前,我正在通过以下放置有效地删除此路线devise_for :users

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

那行得通,但我想有更好的办法了,对吧?

更新资料

正如Benoit Garret所说,在我看来,最好的解决方案是跳过整体创建注册路由,而只创建我真正想要的注册路由。

为此,我先运行rake routes,然后使用输出重新创建想要的内容。最终结果是这样的:

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

注意:

  • :registerable我的User模特儿仍然有
  • devise/registrations 处理更新的电子邮件和密码
  • 更新其他用户属性(权限等)由其他控制器处理

实际答案:

删除默认Devise路径的路由;即:

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

4
我实际上认为您的原始解决方案更加简单明了。安全方面有任何真正的问题吗?
2014年

由于某种原因,您更新后的解决方案不断抛出错误,提示我需要ID。经过一个小时的努力,许多服务器重新启动后,它以某种方式自行修复。我不知道...但是,如果有人遇到这种情况,请继续尝试!
Erik Trautman 2014年

@counterbeing-我知道没有问题,我只是不喜欢拥有未使用的路线或依赖订购。
弥敦道(Nathan Long)

1
如果“实际答案”无法从设计控制器中重定向到该路由,则无法杀死该路由。如果您点击GET route like,默认行为仍会将您引导至注册路径https://example.com/users/。请参阅下面的答案。
lacostenycoder

1
安全漏洞!所显示的“实际答案”仅摆脱了注册表单,而没有摆脱实际上创建用户的POST路由。
Eric Terry

Answers:


54

我也尝试这样做,但是在设计google小组中的一个线程劝阻我不要寻找真正干净的解决方案。

我引用JoséValim(Devise维护者):

没有简单的选择。您可以提供补丁,也可以使用:skip =>:registerable并仅添加所需的路由。

最初的问题是:

有什么好的方法可以从Rails中删除特定的路由(删除路由)?


4
完全正确。实际上,我提出了一个补丁,他礼貌地拒绝了:“今天,您可以跳过整个控制器。从使用角度来看,这不是最佳选择,但是手动为整个控制器设置路由非常简单。我相信排除路由名称将使路由生成代码更加复杂(比现在已经复杂),因为我们将无法使用Rails助手(例如资源,资源和朋友)”。github.com/plataformatec/devise/issues/…–
Nathan Long

2
我不知道最初写这个答案时是否是这种情况,但是José引文中的代码是错误的。在Devise 3.4.1中:skip => :registrations不是:skip => :registerable
2014年

89

你可以在模型中做到这一点

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

更改为:

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

注意该符号:registerable已删除

就是这样,不需要任何其他操作。所有路线和注册页面的链接也都被神奇地删除了。


21
不幸的是,这也删除了edit_user_registration我需要的前往的路线。正如我所说,“他们仍然应该能够编辑其个人资料。”
森·朗

1
嗯,好吧,我通常会通过安装rails_admin gem来解决localhost:3000/admin此问题,即使删除了可抵抗的对象,用户也可以通过它来编辑帐户。如果这不是可行的解决方案,请看一下CanCan,它可以让您规定谁可以访问资源,哪些人不能访问资源。我倾向于添加“管理员”或“主持人”等角色,并将其他所有人锁定在sign_up页面之外。
stephenmurdoch 2011年

28
使用管理部分(旨在允许编辑任意记录)为用户提供一种编辑自己的个人资料的方式,这是我很久以来一直听到的最糟糕的想法。请没人这样做
Jeremy

如何sign_in在生产中禁用?
WM

30

我遇到了类似的问题,试图删除createnew的devise_invitable路径:

之前:

 devise_for :users

耙路

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

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

耙路

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

注1设计范围https://github.com/plataformatec/devise#configuring-routes

note 2我正在devise_invitable上应用它,但是它将与任何devise * able功能一起使用

重要说明:请注意devise_scope是针对用户而非user?没错,请当心!它可能会给您带来很多痛苦,从而给您带来以下问题:

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]

正是因为我一直在寻找。对于使用此解决方案的其他人,我必须将/:id附加到放置路由定义中。
约翰

21

我发现了另一篇与此类似的文章,并希望分享@chrisnicola给出的答案。在帖子中,他们试图仅阻止生产期间的用户注册。

您也可以修改注册控制器。您可以使用如下所示的内容:

“ 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

这将覆盖devise的控制器,并改用上述方法。他们添加了Flash消息,以防有人以某种方式将其添加到sign_up页面。您还应该能够将重定向更改为您喜欢的任何路径。

同样在“ config / routes.rb”中,您可以添加以下内容:

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

保持这种状态将使您可以使用标准设计编辑个人资料。如果您希望,您仍然可以通过包括

  def update
  end

“ app / controllers / registrations_controller.rb”中


13

这是一个古老的问题-但我最近解决了相同的问题,并提出了比以下方法更优雅的解决方案:

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

并且它为命名路由(如cancel_user_registration)提供了默认名称,而不会过于冗长。

devise_for :users, skip: [:registrations]

# Recreates the Devise registrations routes
# They act on a singular user (the signed in user)
# Add the actions you want in 'only:'
resource :users,
    only: [:edit, :update, :destroy],
    controller: 'devise/registrations',
    as: :user_registration do
  get 'cancel'
end

rake routes 使用默认的devise模块输出:

                  Prefix Verb   URI Pattern                    Controller#Action
        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
  edit_user_registration GET    /users/edit(.:format)          devise/registrations#edit
       user_registration PATCH  /users(.:format)               devise/registrations#update
                         PUT    /users(.:format)               devise/registrations#update
                         DELETE /users(.:format)               devise/registrations#destroy

12

您可以通过将“ devise_scope”放置在“ devise_for”之前来覆盖它。

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

devise_for :users

不确定这是否是最好的方法,但不确定它是我目前的解决方案,因为它只是重定向回到登录页面。


1
我采取了类似的方法,但也希望URL也更改,因此使用`get“ / users / sign_up”,:to => redirect(“ /”)`
dinjas 2014年

如此简单,最简单的解决方案。但是这种解决方法有一分钟的问题。地址保留下来。如果输入,/users/sign_up则可以访问sites#indexnot,sign_up但地址仍然保留/users/sign_up
企鹅2015年

5

我喜欢@max的答案,但是当尝试使用它时,由于devise_mapping为零,我遇到了一个错误。

我将他的解决方案略微修改为似乎可以解决该问题的解决方案。它需要将调用包装到resourceinside 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

注意,devise_scope期望单数,:userresource期望复数:users


4

在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

您现在登录登录页面时会得到一个错误,以进行修复。在以下位置进行更改: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 %>

这对我有用(我只使用了devise_foras块),我不得不:registerable在模型中删除。
dusan 2014年

3

我发现它可以很好地工作,而不会弄乱路由或添加应用程序控制器方法。我的方法是重写devise方法。加上这一点,app/controllers/devise/registrations_controller.rb 为了简洁起见,我省略了其他方法。

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

另外,为了消除从其他视图仍然可以访问此路径的幻想,您可能还想从以下视图中删除此代码 app/views/devise/shared/_links.erb

<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
  <%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end -%>

2

对于其他我的情况。
devise (3.5.2)
我成功删除了注册路线,但是保留了以下代码来编辑配置文件。

#routes.rb
devise_for :users, skip: [:registrations]
as :user do
  get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
  put '/users(.:format)' => 'devise/registrations#update', as: 'user_registration'
  patch '/users(.:format)' => 'devise/registrations#update'
end

1

这是我走的路线略有不同。它使您不必覆盖devise/shared/_links.html.erb视图。

app/models/user.rb

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

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

之前:

$ 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

后:

$ 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

如果您不想使用冗余路由,请跳过所有默认路由,例如devise_for :users, skip: :all
elquimista

0

我遇到了同样的问题,我发现从注册页面重定向用户有点不好的做法。所以我的解决方案基本上是根本不使用:registrable

我要做的是创建一个类似编辑用户详细信息的页面,如下所示:

<%= 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 %>

因此,此表单将提交到更新密码的新发布端点中,如下所示:

  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

稍后,您可以@result在视图中使用来告诉用户密码是否已更新。


0

通过更改路线,随之而来的还有很多其他问题。我发现最简单的方法是执行以下操作。

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

可行,但是您真的想对每个动作都运行此方法吗?
lacostenycoder

-7

您可以修改devisegem本身。首先,运行以下命令以找到使用以下命令的安装位置:

gem which devise

让我们假设路径是: /usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise

然后去

/usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise/lib/devise/railsroutes.rb在该目录中进行编辑。有一个称为的方法def devise_registration(mapping, controllers),您可以修改该方法以摆脱新操作。您也可以完全删除的映射devise_registration


+1是一个替代建议,但是对我而言,分叉gem似乎比在路线中添加一些笨拙的代码更不理想。
内森·朗

4
在一般情况下,这是很大的禁忌!您应该保持宝石原样,如果您需要更改某些东西,只需猴子修补它们即可
相当于

在这种情况下,我同意您的意见,但总的来说,我不认为您应该回避对在许多不同地方用作猴子补丁代码替代方法的库/宝石进行更改。根据您的需要来模制库的能力是使用开源代码IMO的一大优点。
Ankit Soni 2012年

如果要修改gem,请至少将其分叉并将Gemfile指向猴子修补的gem(例如在github上)。我已经几次这样做了。过程是:fork gem,在本地克隆fork,monkey修补本地版本,推送到远程仓库,然后将Gemfile指向它。(ie gem 'devise', github: 'yourusername/devise', branch: "master"
lacostenycoder
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.