rails before_destroy部分删除

时间:2012-10-30 12:10:58

标签: ruby-on-rails-3 model

我正试图找出一种方法来部分删除/销毁rails中的依赖模型。

代码看起来像这样:

class User < ActiveRecord::Base

  has_many :subscriptions
  has_many :photos, :dependent => :destroy
  has_many :badges, :dependent => :destroy

  before_destroy :partial_destroy

  def partial_destroy
    self.photos.destroy_all
    self.badges.destroy_all
    return false if self.subscriptions.any? 
  end
...

基本上,我想破坏照片和徽章,但如果用户有任何订阅,我想保留这些订阅,并且还防止用户被破坏。

我尝试使用.each { |obj| obj.destroy }并使用deletedelete_all,但似乎并不重要。

before_destroy返回false时,看起来rails正在执行某种回滚。有没有办法摧毁部分家属而不是其他人?

2 个答案:

答案 0 :(得分:1)

这是旧的,所以我希望你已经忘记了它,但我偶然发现了它。

我并不感到惊讶deletedelete_all没有用,因为那些bypass callbacks

你完全正确Rails performs a rollback if any before_ callback returns false。由于Rails将整个回调链包装在一个事务中,因此您无法在链中执行数据库调用(如销毁)。我建议的是在回调中添加一个条件:

  • 如果用户有订阅,请启动后台作业,稍后将进行部分删除(在回调事务之外),并从回调中返回false。
  • 如果他们没有订阅,则您不会启动后台作业,从回调中返回true,并像往常一样销毁您的模型。

答案 1 :(得分:1)

我最终做了以下事情:

  • destroy模型上覆盖User(见下文)
  • 实际上并未删除User,而是销毁不需要的家属,并清空User模型本身的任何字段,例如电子邮件。
  • 我创建了一个UserDeleter类,它接管用户并执行所有清算操作,只是为了让事情更清洁/具有某种单一责任

覆盖destroy

  def destroy
    run_callbacks(:destroy) do
      UserDeleter.new(self).delete
    end
  end

删除依赖项并清除用户

上的数据
class UserDeleter

  def initialize(user)
    @user = user
  end

  def delete
    delete_photos
    delete_badges
    clear_personal_data
    # ...
  end

  private

  def delete_photos
    @user.photos.destroy_all
  end

  def clear_personal_data
    @user.update_attributes!(
      :email => deleted_email,
      :nickname => '<deleted>')
  end

  def deleted_email
    "deleted@#{random_string}.com"
  end

  def random_string(length = 20)
    SecureRandom.hex(length)[0..length]
  end
#...
end