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.)
Would you like to see more Elixir content like this? Sign up to my mailing list so I can gauge how much interest there is in this type of content.