如何删除设计路线以进行注册?
Posted
技术标签:
【中文标题】如何删除设计路线以进行注册?【英文标题】:How do I remove the Devise route to sign up? 【发布时间】:2011-10-07 17:44:15 【问题描述】:我在 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
注意:
我的User
模型中还有:registerable
devise/registrations
处理更新电子邮件和密码
更新其他用户属性 - 权限等 - 由不同的控制器处理
实际答案:
删除默认设计路径的路线;即:
devise_for :users, path_names:
sign_up: ''
【问题讨论】:
我实际上认为您的原始解决方案更加简单明了。安全方面有什么真正的问题吗? 由于某种原因,您更新的解决方案不断抛出错误,提示我需要 ID。经过一个小时的拉扯和许多服务器重新启动后,它以某种方式自行修复。我不知道...但是如果其他人遇到这种情况,请继续尝试! @counterbeing - 据我所知没问题,我只是不喜欢有未使用的路线或依赖订购。 “实际答案”如果从设计控制器内重定向到,则不会完成终止路由。如果您点击https://example.com/users/
之类的 GET 路由,默认行为仍会将您路由到注册路径。请参阅下面的答案。
安全漏洞!显示的“实际答案”只是摆脱了注册表单,并没有摆脱实际创建用户的 POST 路由。
【参考方案1】:
你可以在你的模型中做到这一点
# typical devise setup in User.rb
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
改成:
devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable
请注意符号 :registerable
已被删除
就是这样,不需要其他任何东西。注册页面的所有路由和链接也被神奇地删除了。
【讨论】:
不幸的是,这也删除了我需要的到edit_user_registration
的路由。正如我所说,“他们应该仍然能够编辑他们的个人资料。”
啊,好吧,我通常通过安装rails_admin gem 来解决这个问题,它让用户可以转到localhost:3000/admin
编辑他们的帐户,即使移除了可抵抗对象。如果这不是一个可行的解决方案,请查看CanCan,它可以让您规定谁可以和不能访问资源。我倾向于添加诸如“管理员”或“版主”之类的角色,并将其他所有人锁定在注册页面之外。
使用管理部分(用于编辑任意记录)为用户提供编辑自己的个人资料的方式是我很长时间以来听到的最糟糕的想法。请不要这样做
如何在生产环境中禁用sign_in
?【参考方案2】:
我也尝试过这样做,但 a thread on the devise google group 劝阻我不要寻找真正干净的解决方案。
我将引用 José Valim(Devise 维护者):
没有直接的选择。您可以提供补丁 或使用 :skip => :registerable 并仅添加您想要的路线。
原来的问题是:
有什么好的方法可以删除特定的路由(delete route) 来自 Rails?
【讨论】:
非常正确。事实上,我提出了一个补丁,他婉言谢绝了:“今天可以跳过整个控制器。从使用上来说不是最优的,但是手动设置整个控制器的路由很简单。我相信排除路由顾名思义,这只会使路由生成代码变得更复杂(比现在更复杂),因为我们将无法使用 Rails 助手(如资源、资源和朋友)”。 github.com/plataformatec/devise/issues/… 我不知道最初编写此答案时是否是这种情况,但是 José 引用中的代码是错误的。在设计 3.4.1 中,它是:skip => :registrations
而不是 :skip => :registerable
。【参考方案3】:
我有类似的问题试图删除 create 和 new 的 devise_invitable 路径:
之前:
devise_for :users
rake 路线
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
rake 路线
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
注意 2 我将它应用于 devise_invitable 但它适用于任何设计 *able 功能
重要提示:看到 devise_scope 是在 user 而不是 users 上?没错,注意这个!给你这个问题可能会给你带来很多痛苦:
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 附加到 put 路由定义。【参考方案4】:我发现another post 与此类似,并想分享@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
这将覆盖设计的控制器并使用上述方法。他们添加了 Flash 消息,以防有人以某种方式进入注册页面。您还应该能够将重定向更改为您喜欢的任何路径。
您也可以在 "config/routes.rb" 中添加:
devise_for :users, :controllers => :registrations => "registrations"
保持这种状态将允许您使用标准设计编辑您的个人资料。如果您希望仍然可以通过包含
来覆盖编辑配置文件选项 def update
end
在“app/controllers/registrations_controller.rb”
中【讨论】:
【参考方案5】:您可以通过将“devise_scope”放在“devise_for”之前来覆盖它。
devise_scope :user do
get "/users/sign_up", :to => "sites#index"
end
devise_for :users
不确定这是否是最好的方法,但它目前是我的解决方案,因为它只是重定向回登录页面。
【讨论】:
我采用了类似的方法,但希望 URL 也能改变,所以使用 `get "/users/sign_up", :to => redirect("/")` 如此简单易行的解决方案。但是这个解决方案有一分钟的问题。地址保留。如果您输入/users/sign_up
,那么您将可以访问sites#index
而不是sign_up
,但地址仍然是/users/sign_up
。【参考方案6】:
这是一个老问题 - 但我最近解决了同样的问题并提出了一个比以下更优雅的解决方案:
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
使用默认设计模块输出:
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
【讨论】:
【参考方案7】:我喜欢@max 的answer,但是在尝试使用它时我遇到了一个错误,因为devise_mapping
为nil。
我将他的解决方案稍微修改为似乎可以解决问题的解决方案。它需要将对resource
的调用封装在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
需要单数 :user
而resource
需要复数 :users
。
【讨论】:
【参考方案8】:在 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_for
和 as
块),我必须在模型中删除 :registerable
。【参考方案9】:
我发现这可以很好地工作,而不会弄乱路由或添加应用程序控制器方法。我的方法是覆盖设计方法。将此添加到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 -%>
【讨论】:
【参考方案10】:对于我的其他人来说。
与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
【讨论】:
【参考方案11】:这是我走的稍微不同的路线。它使您不必覆盖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
【参考方案12】:
而不是寻找一个硬性的解决方案。我使用了以下方法。
从页面(路径 devise/registrations/new.html.erb)中删除 sign_up 表单并将其替换为自定义信息。
将传入流量重定向到其他页面。如下routes.rb
get "/users/sign_up", to: redirect('/')
post "/users/sign_up", to: redirect('/')
一定要写在devise_for :users
之前
【讨论】:
【参考方案13】:我遇到了同样的问题,我发现从注册页面重定向用户有点不好。所以我的解决方案基本上是根本不使用: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
告诉用户密码是否已更新。
【讨论】:
【参考方案14】:通过更改路线会带来一大堆其他问题。我发现的最简单的方法是执行以下操作。
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
【讨论】:
有效,但你真的想在每一个动作上运行这个方法吗?【参考方案15】:您可以修改 devise
gem 本身。首先,运行这个命令找到安装使用的位置:
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/rails
并在该目录中编辑routes.rb
。有一个名为def devise_registration(mapping, controllers)
的方法,您可以对其进行修改以摆脱新操作。您还可以完全删除 devise_registration
的映射
【讨论】:
+1 以获得替代建议,但与在我的路线中添加一些笨拙的代码相比,分叉 gem 似乎不太理想。 在一般实践中这是一个很大的禁忌!你应该保持宝石原样,如果你需要改变一些东西,只需猴子修补它们 在这种情况下我同意你的看法,但总的来说,我认为你不应该回避对你使用的库/宝石进行更改,以替代在一堆不同的地方修补代码.根据您的需要构建库的能力是使用开源代码 IMO 的一大优势。 如果你要修改 gem,至少 fork 并将你的 Gemfile 指向你的猴子补丁 gem(例如在 github 上)。我已经多次这样做了。过程是:fork gem,在本地克隆你的 fork,猴子补丁你的本地版本,推送到你的远程 repo 并将 Gemfile 指向它。 (即gem 'devise', github: 'yourusername/devise', branch: "master"
)以上是关于如何删除设计路线以进行注册?的主要内容,如果未能解决你的问题,请参考以下文章