forked from mongodb/mongoid
-
Notifications
You must be signed in to change notification settings - Fork 22
/
paranoia.rb
104 lines (93 loc) · 2.87 KB
/
paranoia.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# encoding: utf-8
module Mongoid #:nodoc:
# Include this module to get soft deletion of root level documents.
# This will add a deleted_at field to the +Document+, managed automatically.
# Potentially incompatible with unique indices. (if collisions with deleted items)
#
# @example Make a document paranoid.
# class Person
# include Mongoid::Document
# include Mongoid::Paranoia
# end
module Paranoia
extend ActiveSupport::Concern
included do
field :deleted_at, :type => Time
end
# Delete the paranoid +Document+ from the database completely. This will
# run the destroy callbacks.
#
# @example Hard destroy the document.
# document.destroy!
def destroy!
run_callbacks(:destroy) { delete! }
end
# Delete the paranoid +Document+ from the database completely.
#
# @example Hard delete the document.
# document.delete!
def delete!
@destroyed = true
Persistence::Operations.remove(self).persist
end
# Delete the +Document+, will set the deleted_at timestamp and not actually
# delete it.
#
# @example Soft remove the document.
# document.remove
#
# @param [ Hash ] options The database options.
#
# @return [ true ] True.
def remove(options = {})
now = Time.now
collection.update({ :_id => id }, { '$set' => { :deleted_at => now } })
@attributes["deleted_at"] = now
true
end
alias :delete :remove
# Determines if this document is destroyed.
#
# @example Is the document destroyed?
# person.destroyed?
#
# @return [ true, false ] If the document is destroyed.
def destroyed?
@destroyed || !!deleted_at
end
# Restores a previously soft-deleted document. Handles this by removing the
# deleted_at flag.
#
# @example Restore the document from deleted state.
# document.restore
def restore
collection.update({ :_id => id }, { '$unset' => { :deleted_at => true } })
@attributes.delete("deleted_at")
end
module ClassMethods #:nodoc:
# Override the default +Criteria+ accessor to only get existing
# documents. Passes all arguments up to +NamedScope.criteria+
#
# @example Override the criteria.
# Person.criteria
#
# @param [ Array ] args The arguments.
#
# @return [ Criteria ] The paranoid compliant criteria.
def criteria(embedded = false, scoped = true)
scoped ? super.where(:deleted_at.exists => false) : super
end
# Find deleted documents
#
# @example Find deleted documents.
# Person.deleted
# Company.first.employees.deleted
# Person.deleted.find("4c188dea7b17235a2a000001").first
#
# @return [ Criteria ] The deleted criteria.
def deleted
where(:deleted_at.exists => true)
end
end
end
end