Reputation: 1985
In Rails 5, I believe the only way to prevent destroy is to call throw(:abort)
; and this is working as expected. The issue I am having, however, is if the record does not meet requirements, rather than destroying it I want to modify the record. However with throw(:abort)
the entire transaction is reverted, undoing any changes the record has received.
Any suggestions on how to achieve this?
class Thing < ApplicationRecord
before_destroy :can_destroy?
private
def can_destroy?
if model.something?
self.update(something: 'foo') # This part is not being retained.
throw(:abort)
end
end
Upvotes: 2
Views: 748
Reputation: 1984
The problem that you're encountering is that ActiveRecord wraps all of your before/after callbacks in transactions to ensure that if any of them fail, no results will be committed to the database. Sadly, you want to do exactly what it's trying to protect you from. There isn't really a "good" way of doing this (that I'm aware of) but a bit of a hack to get around this restriction would be to do your update in an after_rollback
callback, because your throw(:abort)
will cause a transaction rollback. For example:
class Thing < ApplicationRecord
before_destroy :can_destroy?
after_rollback :can_destroy_callbacks
private
def can_destroy?
if model.something?
@update_later = true
throw(:abort)
end
end
def can_destroy_callbacks
if @update_later
update(something: 'foo')
end
end
end
Upvotes: 1