Daniela
Daniela

Reputation: 366

Removing/destroying child object that belongs_to 2 parents

class Concert < ActiveRecord::Base
    has_many :documents, :uniq => true 
    accepts_nested_attributes_for :documents #???, :allow_destroy => true

class Artist < ActiveRecord::Base
    has_one :document, :validate => true
    accepts_nested_attributes_for :document #???, :allow_destroy => true

class Document < ActiveRecord::Base
    belongs_to :artist  
    belongs_to :concert

I want to remove a document from concerts: Destroy it, if its only parent is a concert, but set concert_id to nil and save document, if it also belongs_to an artist. (and analogue idea from artist point of view)

I would like to either:

Or even better:

I have explored polymorphic associations, but I need the SAME document to belong_to 2 parents.

Have lost the plot if it makes any difference, but for completeness sake: Concert and Artist are in a has_many :through => :engagements association

Adding this in Concert (and analogue in Artist) as before_save callbacks works:

def documents_for_deletion?
  self.documents.each do |doc| 
    if doc.marked_for_destruction?
      unless doc.artist_id.blank?
        doc.reload
        doc.concert_id = nil
      end
    end
  end
end

http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html

Is there a way to do it in Document as a before_destroy callback? (which I would prefer, see above)

Upvotes: 1

Views: 529

Answers (1)

BroiSatse
BroiSatse

Reputation: 44715

You can use association callbacks, like after_remove:

class Concert < ActiveRecord::Base
  has_many :documents, :uniq => true, :after_remove => :destroy_document_with_no_parent

def destroy_document_with_no_parent(removed_document)
  removed_document.destroy unless removed_document.concert_id || removed_document.artist_id
end

You probably should place the method in some helper so you wouldn't need to repeat the code in two classes.

Upvotes: 1

Related Questions