如何用Devise“软删除”用户

问题描述:

我目前在Rails项目中使用Devise进行用户注册/身份验证。当用户想要取消他们的账户时,用户对象被销毁,这使我的应用程序处于不希望的状态。如何用Devise“软删除”用户

什么是实施“软删除”的最简单方法,即只删除个人数据并将用户标记为已删除?我仍然想保留所有的记录关联。

我假设我将不得不首先为用户引入一个新的“已删除”列。但后来我坚持在用户的个人资料查看此默认代码:

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

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

+0

删除用户时应该发生什么?他的所有帖子/活动是否应该被删除? – khelll 2011-02-28 10:25:03

+0

我想保留与其他对象的所有关联,但只删除个人数据(名称/电子邮件地址)并禁用登录。 – slhck 2011-02-28 10:34:00

我可以建议覆盖您的用户模型中的destroy方法,以简单地执行update_attribute(:deleted_at, Time.current)(而不是实际销毁),但这种与标准API的偏差可能在未来变得繁重,因此以下是如何修改控制器。

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

class RegistrationsController < Devise::RegistrationsController 
end 

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

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

这似乎很奇怪,但它很有意义,因为默认情况下它是'设计/注册',而不仅仅是'注册'。

下一步是重写注册控制器中的destroy操作。当您使用registration_path(:user), :method => :delete - 这是它链接的地方。到destroy注册控制器的行动。

目前设计做到以下几点。

def destroy 
    resource.destroy 
    set_flash_message :notice, :destroyed 
    sign_out_and_redirect(self.resource) 
end 

我们可以改用此代码。首先让我们给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 

现在你应该全部设置。使用范围来过滤已删除的用户。

+0

谢谢对于答案,我已经能够用你的输入做出我自己的解决方案! – slhck 2011-02-28 12:11:52

+1

非常感谢您的答复!请修正错字:** update_attribtue ** – kravc 2012-02-22 13:28:00

+2

如何让用户稍后使用同一封电子邮件重新注册? – 2013-05-04 19:09:21

您可以使用acts_as_paranoid作为您的用户模型,该模型设置deleted_at而不是删除对象。

+0

我以前听过那个。它如何与Devise进行互动?除了安装'acts_as_paranoid'之外,我需要改变什么? – slhck 2011-02-28 10:35:05

+0

@shick ...您应该将'acts_as_paranoid'行添加到您的用户模型(或任何其他需要软删除的模型)。 – rubyprince 2011-02-28 11:05:46

+1

这个宝石有很多的分支/版本,我找不到一个适用于Rails 3.2.x的工具。 – 2012-12-10 14:38:39

添加到hakunin's answer

为了防止“软删除”用户登录,覆盖active_for_authentication?User型号:

def active_for_authentication? 
    super && !deleted_at 
end 
+3

+1从当前会话中删除新删除的用户的正确钩子。 – 2011-11-23 17:45:28

+2

这真的是最好的答案。 [这里是文档](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Authenticatable)。 – 2012-12-10 19:29:40

+6

感谢您的支持,我唯一不喜欢的部分是与未确认帐户共享的消息。看到我的答案如何更改该消息:http://*.com/a/14966003/637094 – Leito 2013-02-19 19:47:58

一个完整的教程可以在Soft Delete a Devise User Account的设计wiki页面上找到。

摘要:
1.添加 “deleted_at” DATETIME列
2.覆盖用户/注册#摧毁你的路由
3.覆盖用户/注册#消灭在注册控制器
4.更新用户带soft_delete的型号&检查用户是否在认证时处于活动状态
5.添加自定义删除消息