Module: ConcernsOnRails::Models::SoftDeletable::ClassMethods

Includes:
Support::ColumnGuard
Defined in:
lib/concerns_on_rails/models/soft_deletable.rb

Overview

A real module (not class_methods do) so the batch helpers and their private fast-path predicate aren't constrained by Metrics/BlockLength (the Stateable/Auditable precedent). ActiveSupport::Concern auto-extends it.

Instance Method Summary collapse

Methods included from Support::ColumnGuard

#ensure_columns!, #ensure_columns_on!, #schema_reachable?

Instance Method Details

#destroy_allObject

Override destroy_all to soft delete. Kept for backwards compatibility, but prefer the explicit soft_delete_all — silently redefining a standard AR method is a known footgun (and unlike AR's destroy_all this returns a count, not the records).



83
84
85
# File 'lib/concerns_on_rails/models/soft_deletable.rb', line 83

def destroy_all
  soft_delete_all
end

#really_destroy_allObject

Hard-delete every record matching the CURRENT relation — including soft-deleted rows (only the soft-delete column's predicates are peeled off). Note that unscope also drops a caller's own condition on that column, so only_deleted.really_destroy_all widens to the whole relation — use soft_deleted.delete_all to purge trash only. (Before 1.22 this ignored the relation entirely and hard-deleted the complete table.)



94
95
96
# File 'lib/concerns_on_rails/models/soft_deletable.rb', line 94

def really_destroy_all
  all.unscope(where: soft_delete_field).delete_all
end

#restore_allObject

Restore every soft-deleted record (mirror of soft_delete_all): Integer count, RecordNotSaved + rollback on failure, single UPDATE when the fast path applies.



101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/concerns_on_rails/models/soft_deletable.rb', line 101

def restore_all
  return soft_deleted.update_all(soft_delete_field => nil) if soft_delete_batch_fast_path?(:restore)

  transaction do
    soft_deleted.to_a.count do |record|
      record.restore! ||
        raise(ActiveRecord::RecordNotSaved.new(
                "ConcernsOnRails::Models::SoftDeletable: failed to restore record", record
              ))
      true
    end
  end
end

#soft_deletable_by(field = nil, touch: true, default_scope: true) ⇒ Object

Define soft delete field and options. Example:

soft_deletable_by :deleted_at, touch: false
soft_deletable_by :deleted_at, default_scope: false  # don't hide deleted rows from .all


49
50
51
52
53
54
# File 'lib/concerns_on_rails/models/soft_deletable.rb', line 49

def soft_deletable_by(field = nil, touch: true, default_scope: true)
  self.soft_delete_field = field || :deleted_at
  self.soft_delete_touch = touch
  self.soft_delete_default_scope = default_scope
  ensure_columns!("ConcernsOnRails::Models::SoftDeletable", soft_delete_field)
end

#soft_delete_allObject

Soft-delete every matching record. Returns the Integer count of records transitioned (already-deleted rows are skipped and keep their original timestamp). A record that fails raises ActiveRecord::RecordNotSaved and rolls the whole batch back — before 1.22 the rollback happened silently and the method returned nil. With touch: false and no overridden hooks this is a single UPDATE.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/concerns_on_rails/models/soft_deletable.rb', line 62

def soft_delete_all
  if soft_delete_batch_fast_path?(:soft_delete)
    return all.where(soft_delete_field => nil).update_all(soft_delete_field => Time.zone.now)
  end

  transaction do
    all.to_a.count do |record|
      next false if record.deleted?

      record.soft_delete! ||
        raise(ActiveRecord::RecordNotSaved.new(
                "ConcernsOnRails::Models::SoftDeletable: failed to soft-delete record", record
              ))
      true
    end
  end
end