Skip to content

Instantly share code, notes, and snippets.

@masasakano
Created June 25, 2021 12:28
Show Gist options
  • Select an option

  • Save masasakano/f2dae1c6bedae430da4f9ae3f3277727 to your computer and use it in GitHub Desktop.

Select an option

Save masasakano/f2dae1c6bedae430da4f9ae3f3277727 to your computer and use it in GitHub Desktop.
Ruby-on-Rails model helper methods to get dependent children of a record, maybe only those that are not cascade-destroyed.
module ApplicationHelper
# to check whether a record has any dependent children
#
# @see https://stackoverflow.com/a/68129947/3577922
#
def has_children?
## This would be simpler though may initiate more SQL calls:
# self.class.reflect_on_all_associations.map{ |a| self.send(a.name).any? }.any?
self.class.reflect_on_all_associations.each{ |a| return true if self.send(a.name).any? }
false
end
# to check whether a record has any dependent children that
# would not be cascade-destroyed.
#
# @see has_children?
# @see undestroyable_associations
#
# @param skip_nullify: [Boolean] if true (Def), "dependent: :nullify"
# will be treated the same as ":destroy", namely they are not counted as "undestroyable".
def has_undestroyable_children?(**kwd)
undestroyable_associations(**kwd).each{ |a| return true if self.send(a.name).any? }
false
end
# Returns all undestroyable children
#
# @see undestroyable_associations
#
# @return [Array<ApplicationRecord>]
def undestroyable_children(**kwd)
undestroyable_associations(**kwd).map{ |a| self.send(a.name) }.flatten
false
end
# Returns an Array of associations that may contain dependent children that
# would not be cascade-destroyed.
#
# For example, a user alywas has a role, the association record of which
# would be destroyed as soon as the user is removed from the DB.
# That is normal and needs no caution.
# By contrast, if a user owns an article that would not be cascade-destroyed,
# deleting of the user must be treated with caution.
#
# This method returns the associations that fall into the latter.
#
# @see has_undestroyable_children?
#
# @param skip_nullify: [Boolean] if true (Def), "dependent: :nullify"
# will be treated the same as ":destroy", namely they are not counted as "undestroyable".
# @return [Array<ActiveRecord::Reflection>]
def undestroyable_associations(skip_nullify: true)
destroy_keys = %i(destroy delete destroy_async)
destroy_keys.push(:nullify) if skip_nullify
# Note: the other potentials: [:restrict_with_exception, :restrict_with_error]
self.class.reflect_on_all_associations.filter{|i|
opts = i.options
(!(opts.has_key?(:through) && opts[:through]) &&
!(opts.has_key?(:dependent) && destroy_keys.include?(opts[:dependent])))
}
end
private :undestroyable_associations
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment