Удалить осиротевшего родителя - PullRequest
11 голосов
/ 03 мая 2011

У меня есть такие отношения:

Parent
  has_many :children

Child
  belongs_to :parent

Что я хочу сделать, это удалить родителя, если больше не осталось детей.Поэтому для этого у меня есть:

Child
    before_destroy :destroy_orphaned_parent

    def destroy_orphaned_parent
      parent.children.each do |c|
        return if c != self
      end
      parent.destroy
    end

Это прекрасно работает, однако я также хочу каскадно удалить родительский объект для дочернего элемента.Например, я обычно делал бы:

Parent
  has_many :children, :dependent => :destroy

Это вызывает сбой сервера WebRick при тестировании.Я предполагаю, что это происходит из-за бесконечного цикла последнего потомка, удаляющего родителя, удаляющего потомка и т. Д.

Я начинаю думать, что есть лучший способ сделать это?У кого-нибудь есть идеи?Есть ли способ предотвратить эту рекурсию?

Ответы [ 5 ]

8 голосов
/ 16 декабря 2012

Я выполнил это следующим образом:

  before_destroy :find_parent
  after_destroy :destroy_orphaned_parent

  def find_parent
    @parent = self.parent
  end

  def destroy_orphaned_parent
    if @parent.children.length == 0
      @parent.destroy
    end  
  end

По предложению Анвара это также может быть выполнено с помощью обратного вызова around, как указано ниже:

  around_destroy :destroy_orphaned_parent

  def destroy_orphaned_parent
    parent = self.parent
    yield # executes a DELETE database statement
    if parent.children.length == 0
      parent.destroy
    end  
  end

Iне тестировали вышеуказанное решение, поэтому при необходимости обновите его.

7 голосов
/ 03 мая 2011

Некоторые идеи:

  • Вы можете удалить родителей-сирот в after_destroy (найдите их, используя утверждение типа http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/a3f12d578f5a2619)

  • Вы можете установить некоторую переменную экземпляра в before_destroy, содержащую идентификатор родителя, затем выполнить поиск на основе этого идентификатора в обратном вызове after_destroy и решить, удалять ли там родительский объект, основываясь на подсчете дочерних элементов

3 голосов
/ 04 мая 2015

Вы можете сделать это, используя around_destroy callback

around_destroy :destroy_orphaned_parent

def destroy_orphaned_parent
  @parent = self.parent
  yield
  @parent.destroy if @parent.children.length == 0
end
3 голосов
/ 25 октября 2013

Использование обратного вызова after_destroy.

after_destroy :release_parent

def release_parent
  if parent.children.count.zero?
    parent.destroy
  end
end

Использование Rails 3.2.15

0 голосов
/ 13 марта 2015
after_destroy :destroy_parent, if: parent_is_orphan?

private

def parent_is_orphan?
 parent.children.count.zero?
end

def destroy_parent
 parent.destroy
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...