1

我试图找出一种方法来部分删除/销毁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 }使用deleteand delete_all,但这似乎无关紧要。

before_destroy每当返回 false时,似乎 Rails 正在执行某种回滚。有没有办法摧毁部分家属而不是其他人?

4

2 回答 2

1

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

我并不感到惊讶delete并且delete_all没有工作,因为那些绕过回调

如果任何回调返回 false , Rails 执行回滚before_是完全正确的。因为 Rails 将整个回调链包装在一个事务中,所以您将无法在链中执行数据库调用(如销毁)。我建议在回调中放置一个条件:

  • 如果用户有订阅,则启动一个后台作业,该作业稍后将执行此部分删除(在回调事务之外),并从回调中返回 false。
  • 如果他们没有订阅,你就不会启动后台作业,从回调中返回 true,然后像往常一样销毁你的模型。
于 2014-08-29T17:04:35.677 回答
1

我最终做了以下事情:

  • 覆盖模型(destroyUser下文)
  • 实际上并没有删除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
于 2014-08-30T08:49:50.773 回答