Module: Paranoia

Defined in:
lib/paranoia.rb,
lib/paranoia/version.rb

Defined Under Namespace

Modules: Query, Relation

Constant Summary collapse

VERSION =
'3.0.1'.freeze

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.default_sentinel_valueObject

Change default values in a rails initializer



12
13
14
# File 'lib/paranoia.rb', line 12

def default_sentinel_value
  @default_sentinel_value
end

.delete_all_enabledObject

Change default values in a rails initializer



12
13
14
# File 'lib/paranoia.rb', line 12

def delete_all_enabled
  @delete_all_enabled
end

Class Method Details

.included(klazz) ⇒ Object



16
17
18
# File 'lib/paranoia.rb', line 16

def self.included(klazz)
  klazz.extend Query
end

Instance Method Details

#get_recovery_window_range(opts) ⇒ Object



157
158
159
160
161
# File 'lib/paranoia.rb', line 157

def get_recovery_window_range(opts)
  return opts[:recovery_window_range] if opts[:recovery_window_range]
  return unless opts[:recovery_window]
  (deletion_time - opts[:recovery_window]..deletion_time + opts[:recovery_window])
end

#paranoia_deleteObject Also known as: delete

Raises:

  • (ActiveRecord::ReadOnlyRecord)


109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/paranoia.rb', line 109

def paranoia_delete
  raise ActiveRecord::ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
  if persisted?
    # if a transaction exists, add the record so that after_commit
    # callbacks can be run
    add_to_transaction
    update_columns(paranoia_destroy_attributes)
  elsif !frozen?
    assign_attributes(paranoia_destroy_attributes)
  end
  self
end

#paranoia_destroyObject Also known as: destroy



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/paranoia.rb', line 69

def paranoia_destroy
  with_transaction_returning_status do
    result = run_callbacks(:destroy) do
      @_disable_counter_cache = paranoia_destroyed?
      result = paranoia_delete
      next result unless result && ActiveRecord::VERSION::STRING >= '4.2'
      each_counter_cached_associations do |association|
        foreign_key = association.reflection.foreign_key.to_sym
        next if destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key
        next unless send(association.reflection.name)
        association.decrement_counters
      end
      @_trigger_destroy_callback = true
      @_disable_counter_cache = false
      result
    end
    raise ActiveRecord::Rollback, "Not destroyed" unless paranoia_destroyed?
    result
  end || false
end

#paranoia_destroy!Object



91
92
93
94
# File 'lib/paranoia.rb', line 91

def paranoia_destroy!
  paranoia_destroy ||
    raise(ActiveRecord::RecordNotDestroyed.new("Failed to destroy the record", self))
end

#paranoia_destroyed?Boolean Also known as: deleted?

Returns:

  • (Boolean)


168
169
170
# File 'lib/paranoia.rb', line 168

def paranoia_destroyed?
  paranoia_column_value != paranoia_sentinel_value
end

#really_destroy!(update_destroy_attributes: true) ⇒ Object



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/paranoia.rb', line 173

def really_destroy!(update_destroy_attributes: true)
  with_transaction_returning_status do
    run_callbacks(:real_destroy) do
      @_disable_counter_cache = paranoia_destroyed?
      dependent_reflections = self.class.reflections.select do |name, reflection|
        reflection.options[:dependent] == :destroy
      end
      if dependent_reflections.any?
        dependent_reflections.each do |name, reflection|
          association_data = self.send(name)
          # has_one association can return nil
          # .paranoid? will work for both instances and classes
          next unless association_data && association_data.paranoid?
          if reflection.collection?
            next association_data.with_deleted.find_each { |record|
              record.really_destroy!(update_destroy_attributes: update_destroy_attributes)
            }
          end
          association_data.really_destroy!(update_destroy_attributes: update_destroy_attributes)
        end
      end
      update_columns(paranoia_destroy_attributes) if update_destroy_attributes
      destroy_without_paranoia
    end
  end
end

#restore!(opts = {}) ⇒ Object Also known as: restore



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/paranoia.rb', line 123

def restore!(opts = {})
  self.class.transaction do
    run_callbacks(:restore) do
      recovery_window_range = get_recovery_window_range(opts)
      # Fixes a bug where the build would error because attributes were frozen.
      # This only happened on Rails versions earlier than 4.1.
      noop_if_frozen = ActiveRecord.version < Gem::Version.new("4.1")
      if within_recovery_window?(recovery_window_range) && ((noop_if_frozen && !@attributes.frozen?) || !noop_if_frozen)
        @_disable_counter_cache = !paranoia_destroyed?
        write_attribute paranoia_column, paranoia_sentinel_value
        if paranoia_after_restore_commit
          @_trigger_restore_callback = true
          add_to_transaction
        end
        update_columns(paranoia_restore_attributes)
        each_counter_cached_associations do |association|
          if send(association.reflection.name)
            association.increment_counters
          end
        end
        @_disable_counter_cache = false
      end
      restore_associated_records(recovery_window_range) if opts[:recursive]
    end
  end

  self
ensure
  if paranoia_after_restore_commit
    @_trigger_restore_callback = false
  end
end

#transaction_include_any_action?(actions) ⇒ Boolean

Returns:

  • (Boolean)


101
102
103
104
105
106
107
# File 'lib/paranoia.rb', line 101

def transaction_include_any_action?(actions)
  super || actions.any? do |action|
    if action == :restore
      paranoia_after_restore_commit && @_trigger_restore_callback
    end
  end
end

#trigger_transactional_callbacks?Boolean

Returns:

  • (Boolean)


96
97
98
99
# File 'lib/paranoia.rb', line 96

def trigger_transactional_callbacks?
  super || @_trigger_destroy_callback && paranoia_destroyed? ||
    @_trigger_restore_callback && !paranoia_destroyed?
end

#within_recovery_window?(recovery_window_range) ⇒ Boolean

Returns:

  • (Boolean)


163
164
165
166
# File 'lib/paranoia.rb', line 163

def within_recovery_window?(recovery_window_range)
  return true unless recovery_window_range
  recovery_window_range.cover?(deletion_time)
end