如何用Devise"软删除"用户

slh*_*hck 67 ruby authentication ruby-on-rails

我目前在Rails项目中使用Devise进行用户注册/身份验证.当用户想要取消他们的帐户时,用户对象被销毁,这使我的应用程序处于不期望的状态.

实现"软删除"的最简单方法是什么,即仅删除个人数据并将用户标记为已删除?我仍然希望保留所有记录关联.

我假设我必须首先为用户引入一个新的"已删除"列.但是后来我在用户的个人资料视图中遇到了这个默认代码:

<p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.</p>
Run Code Online (Sandbox Code Playgroud)

我在哪里可以找到这种:delete方法?我该如何覆盖默认的Devise方法?

Max*_*yak 103

我可以建议destroy你的用户模型的覆盖方法只是做update_attribute(:deleted_at, Time.current)(而不是实际销毁),但这种与标准API的偏差将来会变得很麻烦,所以这里是如何修改控制器.

Devise有一堆开箱即用的默认控制器.自定义它们的最佳方法是创建自己的控制器,继承相应的设计控制器.在这种情况下,我们正在谈论Devise::RegistrationsController- 通过查看来源很容易识别.所以创建一个新的控制器.

class RegistrationsController < Devise::RegistrationsController
end
Run Code Online (Sandbox Code Playgroud)

现在我们有自己的控制器完全继承了所有设计提供的逻辑.下一步是告诉设计使用它而不是默认设置.在你的路线你devise_for有线.应将其更改为包含注册控制器.

devise_for :users, :controllers => { :registrations => 'registrations' } 
Run Code Online (Sandbox Code Playgroud)

这看起来很奇怪,但这是有道理的,因为默认情况下它是"设计/注册",而不仅仅是"注册".

下一步是覆盖destroy注册控制器中的操作.当你使用registration_path(:user), :method => :delete- 这是它链接的地方.要destroy注册控制器的作用.

目前设计做了以下.

def destroy
  resource.destroy
  set_flash_message :notice, :destroyed
  sign_out_and_redirect(self.resource)
end
Run Code Online (Sandbox Code Playgroud)

我们可以使用此代码.首先让我们为User模型添加新方法.

class User < ActiveRecord::Base
  def soft_delete
    # assuming you have deleted_at column added already
    update_attribute(:deleted_at, Time.current)
  end
end

# Use this for Devise 2.1.0 and newer versions
class RegistrationsController < Devise::RegistrationsController

  def destroy
    resource.soft_delete
    Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
    set_flash_message :notice, :destroyed if is_navigational_format?
    respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
  end
end

# Use this for older Devise versions
class RegistrationsController < Devise::RegistrationsController
  def destroy
    resource.soft_delete
    set_flash_message :notice, :destroyed
    sign_out_and_redirect(resource)
  end
end
Run Code Online (Sandbox Code Playgroud)

现在你应该全力以赴.使用范围过滤掉已删除的用户.

  • 如何让用户稍后使用同一封电子邮件重新注册? (2认同)
  • 确保还覆盖新的会话控制器,以便在他们删除帐户时不允许用户登录. (2认同)

Pey*_*man 90

加入hakunin的答案:

要防止"软删除"用户登录,请覆盖active_for_authentication?您的User模型:

def active_for_authentication?
  super && !deleted_at
end
Run Code Online (Sandbox Code Playgroud)

  • 多亏了这一点,我唯一不喜欢的部分是与未确认帐户共享的消息.请参阅我的答案,了解如何更改该消息:http://stackoverflow.com/a/14966003/637094 (6认同)
  • +1用于指出正确的钩子,它也会从当前会话中踢出新删除的用户. (3认同)
  • 这真是最好的答案.[这是文档](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Authenticatable). (2认同)

rau*_*sch 10

您可以将acts_as_paranoid用于User模型,该模型设置deleted_at而不是删除对象.

  • @IvailoBardarov Rails 3有一个名为paranoia的新宝石:https://github.com/radar/paranoia (3认同)

csi*_*csi 7

可以在Devise wiki页面上的Soft Delete a Devise User Account找到完整的教程.

摘要:
1.添加"deleted_at"DATETIME列
2.覆盖路由中的用户/注册#dure
3.覆盖注册控制器中的用户/注册
#dured 4.使用soft_delete更新用户模型并检查用户是否在验证时处于活动状态
5.添加自定义删除邮件