Leveraging Active Record reflections

I recently ran into an issue using the permanent records gem: when you permanently destroy a record (i.e. NOT soft delete), the dependent records with a `:dependent => :destroy` relationship are only soft deleted (i.e. marked as deleted, but kept in the database). Let’s see how we can implement the desired functionality by leveraging Active Record’s reflections.

Reflections

As described in the API, reflections enable us to “interrogate Active Record classes and objects about their associations and aggregations”. Specifically, in this case, we’re going to see if a given Active Record class has dependents to destroy.

`:dependent => :destroy` is an option on the association, so the information we’re after will reside in the association’s option hash. And since the association’s options are defined at the class level, this is how we get the dependent classes to be destroyed:

@my_instance.class.reflections.each do |reflection|
if reflection.options[:dependent] == :destroy
# do something
end
end

The twist

As you can see in the actual commit, I ended up storing references to the classes and ids of that class that needed to be destroyed. Why? Well, Active Record will call the `destroy` method on each dependent record (via `super`). But since `destroy` only soft deletes records by default (as modified by this very gem), the end result won’t be what we wanted. (In addition, there is no way to pass the :force flag used by the gem to force a hard deletion.)

So instead, we call `super` (which will also run the destroy callbacks on each record), and then we can force the permanent deletion of each dependent record. This shouldn’t be a real performance issue, since permanent deletion should be rare when using permanent records.

(You might want to see the subsequent commit which is related and deals with additional issues.)

This entry was posted in Rails, Ruby. Bookmark the permalink.