module ClosureTree::HierarchyMaintenance
Public Instance Methods
_ct_after_save()
click to toggle source
# File lib/closure_tree/hierarchy_maintenance.rb, line 37 def _ct_after_save as_5_1 = ActiveSupport.version >= Gem::Version.new('5.1.0') changes_method = as_5_1 ? :saved_changes : :changes if public_send(changes_method)[_ct.parent_column_name] || @was_new_record rebuild! end if public_send(changes_method)[_ct.parent_column_name] && !@was_new_record # Resetting the ancestral collections addresses # https://github.com/mceachen/closure_tree/issues/68 ancestor_hierarchies.reload self_and_ancestors.reload end @was_new_record = false # we aren't new anymore. @_ct_skip_sort_order_maintenance = false # only skip once. true # don't cancel anything. end
_ct_before_destroy()
click to toggle source
# File lib/closure_tree/hierarchy_maintenance.rb, line 55 def _ct_before_destroy _ct.with_advisory_lock do delete_hierarchy_references if _ct.options[:dependent] == :nullify self.class.find(self.id).children.find_each { |c| c.rebuild! } end end true # don't prevent destruction end
_ct_before_save()
click to toggle source
# File lib/closure_tree/hierarchy_maintenance.rb, line 32 def _ct_before_save @was_new_record = new_record? true # don't cancel the save end
_ct_skip_cycle_detection!()
click to toggle source
# File lib/closure_tree/hierarchy_maintenance.rb, line 14 def _ct_skip_cycle_detection! @_ct_skip_cycle_detection = true end
_ct_skip_sort_order_maintenance!()
click to toggle source
# File lib/closure_tree/hierarchy_maintenance.rb, line 18 def _ct_skip_sort_order_maintenance! @_ct_skip_sort_order_maintenance = true end
_ct_validate()
click to toggle source
# File lib/closure_tree/hierarchy_maintenance.rb, line 22 def _ct_validate if !(defined? @_ct_skip_cycle_detection) && !new_record? && # don't validate for cycles if we're a new record changes[_ct.parent_column_name] && # don't validate for cycles if we didn't change our parent parent.present? && # don't validate if we're root parent.self_and_ancestors.include?(self) # < this is expensive :\ errors.add(_ct.parent_column_sym, I18n.t('closure_tree.loop_error', default: 'You cannot add an ancestor as a descendant')) end end
delete_hierarchy_references()
click to toggle source
# File lib/closure_tree/hierarchy_maintenance.rb, line 91 def delete_hierarchy_references _ct.with_advisory_lock do # The crazy double-wrapped sub-subselect works around MySQL's limitation of subselects on the same table that is being mutated. # It shouldn't affect performance of postgresql. # See http://dev.mysql.com/doc/refman/5.0/en/subquery-errors.html # Also: PostgreSQL doesn't support INNER JOIN on DELETE, so we can't use that. _ct.connection.execute <<-SQL.squish DELETE FROM #{_ct.quoted_hierarchy_table_name} WHERE descendant_id IN ( SELECT DISTINCT descendant_id FROM (SELECT descendant_id FROM #{_ct.quoted_hierarchy_table_name} WHERE ancestor_id = #{_ct.quote(id)} OR descendant_id = #{_ct.quote(id)} ) #{ _ct.t_alias_keyword } x ) SQL end end
rebuild!(called_by_rebuild = false)
click to toggle source
# File lib/closure_tree/hierarchy_maintenance.rb, line 65 def rebuild!(called_by_rebuild = false) _ct.with_advisory_lock do delete_hierarchy_references unless (defined? @was_new_record) && @was_new_record hierarchy_class.create!(:ancestor => self, :descendant => self, :generations => 0) unless root? _ct.connection.execute <<-SQL.squish INSERT INTO #{_ct.quoted_hierarchy_table_name} (ancestor_id, descendant_id, generations) SELECT x.ancestor_id, #{_ct.quote(_ct_id)}, x.generations + 1 FROM #{_ct.quoted_hierarchy_table_name} x WHERE x.descendant_id = #{_ct.quote(_ct_parent_id)} SQL end if _ct.order_is_numeric? && !@_ct_skip_sort_order_maintenance _ct_reorder_prior_siblings_if_parent_changed # Prevent double-reordering of siblings: _ct_reorder_siblings if !called_by_rebuild end children.find_each { |c| c.rebuild!(true) } _ct_reorder_children if _ct.order_is_numeric? && children.present? end end