【问题标题】:How to "soft delete" user with Devise如何使用设计“软删除”用户
【发布时间】:2011-07-05 16:01:27
【问题描述】:

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

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

我假设我必须首先为用户引入一个新的“已删除”列。但是后来我在用户的配置文件视图中被这个默认代码卡住了:

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

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

【问题讨论】:

  • 用户被删除后会发生什么?应该删除他所有的帖子/活动还是什么?
  • 我想保留与其他对象的所有关联,但只删除个人数据(姓名/电子邮件地址)并禁用登录。

标签: ruby-on-rails ruby authentication


【解决方案1】:

我可以建议在您的 User 模型上覆盖 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 =&gt; :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

现在你应该准备好了。使用范围过滤掉已删除的用户。

【讨论】:

  • 感谢您的回答,我已经能够根据您的意见制定自己的解决方案!
  • 非常感谢您的回答!请更正错字:update_attribtue
  • 我怎样才能让用户稍后使用同一电子邮件重新注册?
  • @elsurudo,我发现这样做:stackoverflow.com/questions/8886317/…
  • 确保还覆盖新的会话控制器,以防止人们在删除帐户后登录。
【解决方案2】:

添加到hakunin's answer:

为防止“软删除”用户登录,请在您的 User 模型上覆盖 active_for_authentication?

def active_for_authentication?
  super && !deleted_at
end

【讨论】:

  • +1 用于指出正确的钩子,该钩子也会将新删除的用户从当前会话中踢出。
  • 这确实是最好的答案。 Here are the docs.
  • 谢谢,我唯一不喜欢的部分是与帐户共享的消息未确认。请参阅我关于如何更改该消息的答案:stackoverflow.com/a/14966003/637094
  • 要添加到 d_either 的参考中,除了 active_for_authentication 之外,您似乎还需要定义 inactive_message?在您的用户模型上。这是为了提供一条消息,说明为什么要进行 active_for_authentication?将返回 false。
  • 如果您想要与实际不存在用户记录一样的验证消息,您可能希望将 inactive_message 定义为:def inactive_message return self.active ? super : I18n.t('devise.failure.not_found_in_database') end
【解决方案3】:

您可以将acts_as_paranoid 用于您的用户模型,它设置一个deleted_at 而不是删除对象。

【讨论】:

  • 我以前听说过那个。它将如何与 Devise 交互?除了安装acts_as_paranoid,我还需要在哪里进行更改?
  • @shick ...您应该将acts_as_paranoid 行添加到您的用户模型(或您需要软删除的任何其他模型)。
  • 这个 gem 有很多分支/版本,我找不到适用于 Rails 3.2.x 的版本
  • @IvailoBardarov Rails 3 有一个名为 paranoia 的新宝石:github.com/radar/paranoia
【解决方案4】:

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

总结:
1. 添加“deleted_at”DATETIME 列
2. 在您的路线中覆盖用户/注册#destroy
3. 在注册控制器中覆盖 users/registrations#destroy
4. 使用 soft_delete 更新用户模型并检查用户是否在身份验证中处于活动状态
5.添加自定义删除消息

【讨论】:

    猜你喜欢
    • 2013-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    相关资源
    最近更新 更多