Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: Delete associated records on object destroy

I have 2 models

 class Deal < ActiveRecord::Base
   has_many :couponizations, dependent: :destroy     
   has_many :coupon_codes, through: :couponizations, source: :coupon_code, dependent: :destroy
   accepts_nested_attributes_for :coupon_codes, allow_destroy: true
 end

and

class CouponCode < ActiveRecord::Base
   has_one :couponization, dependent: :destroy
   has_one :deal, through: :couponization, source: :deal

which are linked by many-to-many relationship

class Couponization < ActiveRecord::Base
   belongs_to :coupon_code
   belongs_to :deal
end

Despite I specified dependent: :destroy option, when I delete deal, coupon codes are not being deleted. However couponizations are deleted successfully. Is there any way to delete associated nested records on object destroy?

like image 450
Ilya Cherevkov Avatar asked Jan 04 '14 19:01

Ilya Cherevkov


People also ask

How do you destroy a record in rails?

Rails delete operation using destroy methodBy using destroy, you can delete the record from rails as well as its other existing dependencies. So in the context of our rails application, if we delete a book record using the destroy function, the authors associated with the book will also be deleted.

What is the difference between delete and destroy in rails?

Basically destroy runs any callbacks on the model while delete doesn't. Deletes the record in the database and freezes this instance to reflect that no changes should be made (since they can't be persisted). Returns the frozen instance.

What is soft delete in Rails?

Deleting something from your database is very common and handled very easily by rails as part of a CRUD action. In some cases, it is useful to create a “soft delete”, meaning that the deleted element will still exist in the database but won't appear to the user.


2 Answers

The options dependent: :destroy is ignored when using with the :through (see doc). You have to do it manually, with a after_destroy callback for example.

 class Deal

   after_destroy :destroy_coupon_codes

   private

   def destroy_coupon_codes
     self.coupon_codes.destroy_all   
   end
 end
like image 139
Baldrick Avatar answered Nov 23 '22 12:11

Baldrick


I recommend using :after_destroy callback, so if destroying some Deal instance fails for whatever reason you don't end up deleting all of its CouponCodes.

Here's an :after_destroy example that should work:

after_destroy { |record|
  CouponCode.destroy(record.coupon_codes.pluck(:id))
}

Make sure to remove dependent: :destroy from has_many :couponizations in the Deals model, because all couponizations will now be destroyed by the has_one :couponization, dependent: :destroy in the CouponCode model.

like image 21
Sbbs Avatar answered Nov 23 '22 14:11

Sbbs