rails prevent deletion of child unless parent is being deleted also
Asked Answered
O

1

8

in Ruby on Rails 4, let's say a parent has many children. When the parent is deleted, the children must also be deleted. Other than that, the child shall not be deleted unless it is an orphan. How to do that?

I tried with the following

class Parent < ActiveRecord::Base
  has_many :children, inverse_of: :parent, dependent: :destroy
end

class Child < ActiveRecord::Base
  belongs_to :parent, inverse_of: :children
  before_destroy :checks
private
  def checks
    not parent # true if orphan
  end
end

With the before_destroy check, however, nothing gets deleted. Is there any way of telling this method if the reason of being called is because parent deletion?

Is this an odd thing to ask for? I mean, preventing deletion of childs.

Oslo answered 14/4, 2014 at 15:27 Comment(1)
Unless your app includes code that deletes children directly, it should be impossible to delete them directly, while still being able to delete them as part of deleting the Parent. I don't understand how you are running into this issue. Could you please be more specific?Eckenrode
C
8

Working from carp's answer from Rails: how to disable before_destroy callback when it's being destroyed because of the parent is being destroyed (:dependent => :destroy), try this:

Child:

belongs_to :parent
before_destroy :prevent_destroy
attr_accessor :destroyed_by_parent

...

private

def prevent_destroy
  if !destroyed_by_parent
    self.errors[:base] << "You may not delete this child."
    return false
  end
end

Parent:

has_many :children, :dependent => :destroy
before_destroy :set_destroyed_by_parent, prepend: true

...

private

def set_destroyed_by_parent
  children.each{ |child| child.destroyed_by_parent = true }
end

We had to do this because we're using Paranoia, and dependent: delete_all would hard-delete rather than soft-delete them. My gut tells me there's a better way to do this, but it's not obvious, and this gets the job done.

Cedillo answered 16/4, 2014 at 15:0 Comment(1)
I had the same problem but with has_one relationship. I solved in a slightly different way, but I also feel there must be a better way to do this. My solutionAffiance

© 2022 - 2024 — McMap. All rights reserved.