cmoran92-paranoia 2.0.2a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/.travis.yml +10 -0
- data/Gemfile +17 -0
- data/LICENSE +17 -0
- data/README.md +208 -0
- data/Rakefile +10 -0
- data/lib/paranoia/rspec.rb +13 -0
- data/lib/paranoia/version.rb +3 -0
- data/lib/paranoia.rb +227 -0
- data/paranoia.gemspec +25 -0
- data/test/paranoia_test.rb +760 -0
- metadata +125 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
source 'https://rubygems.org'
|
|
2
|
+
|
|
3
|
+
gem 'sqlite3', :platforms => [:ruby]
|
|
4
|
+
gem 'activerecord-jdbcsqlite3-adapter', :platforms => [:jruby]
|
|
5
|
+
|
|
6
|
+
platforms :rbx do
|
|
7
|
+
gem 'rubysl', '~> 2.0'
|
|
8
|
+
gem 'rubysl-test-unit'
|
|
9
|
+
gem 'rubinius-developer_tools'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
rails = ENV['RAILS'] || '~> 4.1.4'
|
|
13
|
+
|
|
14
|
+
gem 'rails', rails
|
|
15
|
+
|
|
16
|
+
# Specify your gem's dependencies in paranoia.gemspec
|
|
17
|
+
gemspec
|
data/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Permission is hereby granted, without written agreement and without
|
|
2
|
+
license or royalty fees, to use, copy, modify, and distribute this
|
|
3
|
+
software and its documentation for any purpose, provided that the
|
|
4
|
+
above copyright notice and the following two paragraphs appear in
|
|
5
|
+
all copies of this software.
|
|
6
|
+
|
|
7
|
+
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
|
8
|
+
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
9
|
+
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
|
10
|
+
IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
11
|
+
DAMAGE.
|
|
12
|
+
|
|
13
|
+
THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
|
14
|
+
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
|
16
|
+
ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
|
17
|
+
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
data/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Paranoia
|
|
2
|
+
|
|
3
|
+
Paranoia is a re-implementation of [acts\_as\_paranoid](http://github.com/technoweenie/acts_as_paranoid) for Rails 3 and Rails 4, using much, much, much less code.
|
|
4
|
+
|
|
5
|
+
You would use either plugin / gem if you wished that when you called `destroy` on an Active Record object that it didn't actually destroy it, but just *hide* the record. Paranoia does this by setting a `deleted_at` field to the current time when you `destroy` a record, and hides it by scoping all queries on your model to only include records which do not have a `deleted_at` field.
|
|
6
|
+
|
|
7
|
+
If you wish to actually destroy an object you may call `really_destroy!`. **WARNING**: This will also *really destroy* all `dependent: destroy` records, so please aim this method away from face when using.**
|
|
8
|
+
|
|
9
|
+
If a record has `has_many` associations defined AND those associations have `dependent: :destroy` set on them, then they will also be soft-deleted if `acts_as_paranoid` is set, otherwise the normal destroy will be called.
|
|
10
|
+
|
|
11
|
+
## Installation & Usage
|
|
12
|
+
|
|
13
|
+
For Rails 3, please use version 1 of Paranoia:
|
|
14
|
+
|
|
15
|
+
``` ruby
|
|
16
|
+
gem "paranoia", "~> 1.0"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
For Rails 4, please use version 2 of Paranoia:
|
|
20
|
+
|
|
21
|
+
``` ruby
|
|
22
|
+
gem "paranoia", "~> 2.0"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Of course you can install this from GitHub as well:
|
|
26
|
+
|
|
27
|
+
``` ruby
|
|
28
|
+
gem "paranoia", :github => "radar/paranoia", :branch => "master"
|
|
29
|
+
# or
|
|
30
|
+
gem "paranoia", :github => "radar/paranoia", :branch => "rails4"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then run:
|
|
34
|
+
|
|
35
|
+
``` shell
|
|
36
|
+
bundle install
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Updating is as simple as `bundle update paranoia`.
|
|
40
|
+
|
|
41
|
+
#### Run your migrations for the desired models
|
|
42
|
+
|
|
43
|
+
Run:
|
|
44
|
+
|
|
45
|
+
``` shell
|
|
46
|
+
rails generate migration AddDeletedAtToClients deleted_at:datetime:index
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
and now you have a migration
|
|
50
|
+
|
|
51
|
+
``` ruby
|
|
52
|
+
class AddDeletedAtToClients < ActiveRecord::Migration
|
|
53
|
+
def change
|
|
54
|
+
add_column :clients, :deleted_at, :datetime
|
|
55
|
+
add_index :clients, :deleted_at
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Usage
|
|
61
|
+
|
|
62
|
+
#### In your model:
|
|
63
|
+
|
|
64
|
+
``` ruby
|
|
65
|
+
class Client < ActiveRecord::Base
|
|
66
|
+
acts_as_paranoid
|
|
67
|
+
|
|
68
|
+
# ...
|
|
69
|
+
end
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Hey presto, it's there! Calling `destroy` will now set the `deleted_at` column:
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
``` ruby
|
|
76
|
+
>> client.deleted_at
|
|
77
|
+
# => nil
|
|
78
|
+
>> client.destroy
|
|
79
|
+
# => client
|
|
80
|
+
>> client.deleted_at
|
|
81
|
+
# => [current timestamp]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
If you really want it gone *gone*, call `really_destroy!`:
|
|
85
|
+
|
|
86
|
+
``` ruby
|
|
87
|
+
>> client.deleted_at
|
|
88
|
+
# => nil
|
|
89
|
+
>> client.really_destroy!
|
|
90
|
+
# => client
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
If you want a method to be called on destroy, simply provide a `before_destroy` callback:
|
|
94
|
+
|
|
95
|
+
``` ruby
|
|
96
|
+
class Client < ActiveRecord::Base
|
|
97
|
+
acts_as_paranoid
|
|
98
|
+
|
|
99
|
+
before_destroy :some_method
|
|
100
|
+
|
|
101
|
+
def some_method
|
|
102
|
+
# do stuff
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# ...
|
|
106
|
+
end
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
If you want to use a column other than `deleted_at`, you can pass it as an option:
|
|
110
|
+
|
|
111
|
+
``` ruby
|
|
112
|
+
class Client < ActiveRecord::Base
|
|
113
|
+
acts_as_paranoid column: :destroyed_at
|
|
114
|
+
|
|
115
|
+
...
|
|
116
|
+
end
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
If you want to access soft-deleted associations, override the getter method:
|
|
120
|
+
|
|
121
|
+
``` ruby
|
|
122
|
+
def product
|
|
123
|
+
Product.unscoped { super }
|
|
124
|
+
end
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
If you want to find all records, even those which are deleted:
|
|
128
|
+
|
|
129
|
+
``` ruby
|
|
130
|
+
Client.with_deleted
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
If you want to find only the deleted records:
|
|
134
|
+
|
|
135
|
+
``` ruby
|
|
136
|
+
Client.only_deleted
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
If you want to check if a record is soft-deleted:
|
|
140
|
+
|
|
141
|
+
``` ruby
|
|
142
|
+
client.destroyed?
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
If you want to restore a record:
|
|
146
|
+
|
|
147
|
+
``` ruby
|
|
148
|
+
Client.restore(id)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
If you want to restore a whole bunch of records:
|
|
152
|
+
|
|
153
|
+
``` ruby
|
|
154
|
+
Client.restore([id1, id2, ..., idN])
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
If you want to restore a record and their dependently destroyed associated records:
|
|
158
|
+
|
|
159
|
+
``` ruby
|
|
160
|
+
Client.restore(id, :recursive => true)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
If you want callbacks to trigger before a restore:
|
|
164
|
+
|
|
165
|
+
``` ruby
|
|
166
|
+
before_restore :callback_name_goes_here
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
For more information, please look at the tests.
|
|
170
|
+
|
|
171
|
+
## Acts As Paranoid Migration
|
|
172
|
+
|
|
173
|
+
You can replace the older `acts_as_paranoid` methods as follows:
|
|
174
|
+
|
|
175
|
+
| Old Syntax | New Syntax |
|
|
176
|
+
|:-------------------------- |:------------------------------ |
|
|
177
|
+
|`find_with_deleted(:all)` | `Client.with_deleted` |
|
|
178
|
+
|`find_with_deleted(:first)` | `Client.with_deleted.first` |
|
|
179
|
+
|`find_with_deleted(id)` | `Client.with_deleted.find(id)` |
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
The `recover` method in `acts_as_paranoid` runs `update` callbacks. Paranoia's
|
|
183
|
+
`restore` method does not do this.
|
|
184
|
+
|
|
185
|
+
## Support for Unique Keys with Null Values
|
|
186
|
+
|
|
187
|
+
Most databases ignore null columns when it comes to resolving unique index
|
|
188
|
+
constraints. This means unique constraints that involve nullable columns may be
|
|
189
|
+
problematic. Instead of using `NULL` to represent a not-deleted row, you can pick
|
|
190
|
+
a value that you want paranoia to mean not deleted. Note that you can/should
|
|
191
|
+
now apply a `NOT NULL` constraint to your `deleted_at` column.
|
|
192
|
+
|
|
193
|
+
Per model:
|
|
194
|
+
|
|
195
|
+
```ruby
|
|
196
|
+
# pick some value
|
|
197
|
+
acts_as_paranoid sentinel_value: DateTime.new(0)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
or globally in a rails initializer, e.g. `config/initializer/paranoia.rb`
|
|
201
|
+
|
|
202
|
+
```ruby
|
|
203
|
+
Paranoia.default_sentinel_value = DateTime.new(0)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
This gem is released under the MIT license.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'rspec/expectations'
|
|
2
|
+
|
|
3
|
+
# Validate the subject's class did call "acts_as_paranoid"
|
|
4
|
+
RSpec::Matchers.define :act_as_paranoid do
|
|
5
|
+
match { |subject| subject.class.ancestors.include?(Paranoia) }
|
|
6
|
+
|
|
7
|
+
failure_message { "expected #{subject.class} to use `acts_as_paranoid`" }
|
|
8
|
+
failure_message_when_negated { "expected #{subject.class} not to use `acts_as_paranoid`" }
|
|
9
|
+
|
|
10
|
+
# RSpec 2 compatibility:
|
|
11
|
+
alias_method :failure_message_for_should, :failure_message
|
|
12
|
+
alias_method :failure_message_for_should_not, :failure_message_when_negated
|
|
13
|
+
end
|
data/lib/paranoia.rb
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
require 'active_record' unless defined? ActiveRecord
|
|
2
|
+
|
|
3
|
+
module Paranoia
|
|
4
|
+
@@default_sentinel_value = nil
|
|
5
|
+
|
|
6
|
+
# Change default_sentinel_value in a rails initilizer
|
|
7
|
+
def self.default_sentinel_value=(val)
|
|
8
|
+
@@default_sentinel_value = val
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.default_sentinel_value
|
|
12
|
+
@@default_sentinel_value
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.included(klazz)
|
|
16
|
+
klazz.extend Query
|
|
17
|
+
klazz.extend Callbacks
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module Query
|
|
21
|
+
def paranoid? ; true ; end
|
|
22
|
+
|
|
23
|
+
def with_deleted
|
|
24
|
+
if ActiveRecord::VERSION::STRING >= "4.1"
|
|
25
|
+
unscope where: paranoia_column
|
|
26
|
+
else
|
|
27
|
+
all.tap { |x| x.default_scoped = false }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def only_deleted
|
|
32
|
+
with_deleted.where.not(table_name => { paranoia_column => paranoia_sentinel_value} )
|
|
33
|
+
end
|
|
34
|
+
alias :deleted :only_deleted
|
|
35
|
+
|
|
36
|
+
def restore(id, opts = {})
|
|
37
|
+
Array(id).flatten.map { |one_id| only_deleted.find(one_id).restore!(opts) }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
module Callbacks
|
|
42
|
+
def self.extended(klazz)
|
|
43
|
+
klazz.define_callbacks :restore
|
|
44
|
+
|
|
45
|
+
klazz.define_singleton_method("before_restore") do |*args, &block|
|
|
46
|
+
set_callback(:restore, :before, *args, &block)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
klazz.define_singleton_method("around_restore") do |*args, &block|
|
|
50
|
+
set_callback(:restore, :around, *args, &block)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
klazz.define_singleton_method("after_restore") do |*args, &block|
|
|
54
|
+
set_callback(:restore, :after, *args, &block)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def destroy
|
|
60
|
+
callbacks_result = transaction do
|
|
61
|
+
run_callbacks(:destroy) do
|
|
62
|
+
touch_paranoia_column
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
callbacks_result ? self : false
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# As of Rails 4.1.0 +destroy!+ will no longer remove the record from the db
|
|
69
|
+
# unless you touch the paranoia column before.
|
|
70
|
+
# We need to override it here otherwise children records might be removed
|
|
71
|
+
# when they shouldn't
|
|
72
|
+
if ActiveRecord::VERSION::STRING >= "4.1"
|
|
73
|
+
def destroy!
|
|
74
|
+
destroyed? ? super : destroy || raise(ActiveRecord::RecordNotDestroyed)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def delete
|
|
79
|
+
return if new_record?
|
|
80
|
+
touch_paranoia_column(false)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def restore!(opts = {})
|
|
84
|
+
self.class.transaction do
|
|
85
|
+
run_callbacks(:restore) do
|
|
86
|
+
# Fixes a bug where the build would error because attributes were frozen.
|
|
87
|
+
# This only happened on Rails versions earlier than 4.1.
|
|
88
|
+
noop_if_frozen = ActiveRecord.version < Gem::Version.new("4.1")
|
|
89
|
+
if (noop_if_frozen && !@attributes.frozen?) || !noop_if_frozen
|
|
90
|
+
write_attribute paranoia_column, paranoia_sentinel_value
|
|
91
|
+
update_column paranoia_column, paranoia_sentinel_value
|
|
92
|
+
end
|
|
93
|
+
restore_associated_records if opts[:recursive]
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
self
|
|
98
|
+
end
|
|
99
|
+
alias :restore :restore!
|
|
100
|
+
|
|
101
|
+
def destroyed?
|
|
102
|
+
send(paranoia_column) != paranoia_sentinel_value
|
|
103
|
+
end
|
|
104
|
+
alias :deleted? :destroyed?
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
# touch paranoia column.
|
|
109
|
+
# insert time to paranoia column.
|
|
110
|
+
# @param with_transaction [Boolean] exec with ActiveRecord Transactions.
|
|
111
|
+
def touch_paranoia_column(with_transaction=false)
|
|
112
|
+
# This method is (potentially) called from really_destroy
|
|
113
|
+
# The object the method is being called on may be frozen
|
|
114
|
+
# Let's not touch it if it's frozen.
|
|
115
|
+
unless self.frozen?
|
|
116
|
+
if with_transaction
|
|
117
|
+
with_transaction_returning_status { touch(paranoia_column) }
|
|
118
|
+
else
|
|
119
|
+
touch(paranoia_column)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# restore associated records that have been soft deleted when
|
|
125
|
+
# we called #destroy
|
|
126
|
+
def restore_associated_records
|
|
127
|
+
destroyed_associations = self.class.reflect_on_all_associations.select do |association|
|
|
128
|
+
association.options[:dependent] == :destroy
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
destroyed_associations.each do |association|
|
|
132
|
+
association_data = send(association.name)
|
|
133
|
+
|
|
134
|
+
unless association_data.nil?
|
|
135
|
+
if association_data.paranoid?
|
|
136
|
+
if association.collection?
|
|
137
|
+
association_data.only_deleted.each { |record| record.restore(:recursive => true) }
|
|
138
|
+
else
|
|
139
|
+
association_data.restore(:recursive => true)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
if association_data.nil? && association.macro.to_s == "has_one"
|
|
145
|
+
association_class_name = association.options[:class_name].present? ? association.options[:class_name] : association.name.to_s.camelize
|
|
146
|
+
association_foreign_key = association.options[:foreign_key].present? ? association.options[:foreign_key] : "#{self.class.name.to_s.underscore}_id"
|
|
147
|
+
Object.const_get(association_class_name).only_deleted.where(association_foreign_key, self.id).first.try(:restore, recursive: true)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
clear_association_cache if destroyed_associations.present?
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
class ActiveRecord::Base
|
|
156
|
+
def self.acts_as_paranoid(options={})
|
|
157
|
+
alias :destroy! :destroy
|
|
158
|
+
alias :delete! :delete
|
|
159
|
+
def really_destroy!
|
|
160
|
+
dependent_reflections = self.class.reflections.select do |name, reflection|
|
|
161
|
+
reflection.options[:dependent] == :destroy
|
|
162
|
+
end
|
|
163
|
+
if dependent_reflections.any?
|
|
164
|
+
dependent_reflections.each do |name, _|
|
|
165
|
+
associated_records = self.send(name)
|
|
166
|
+
# has_one association can return nil
|
|
167
|
+
if associated_records && associated_records.respond_to?(:with_deleted)
|
|
168
|
+
# Paranoid models will have this method, non-paranoid models will not
|
|
169
|
+
associated_records.with_deleted.each(&:really_destroy!)
|
|
170
|
+
self.send(name).reload
|
|
171
|
+
elsif associated_records && !associated_records.respond_to?(:each) # single record
|
|
172
|
+
associated_records.really_destroy!
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
touch_paranoia_column if ActiveRecord::VERSION::STRING >= "4.1"
|
|
177
|
+
destroy!
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
include Paranoia
|
|
181
|
+
class_attribute :paranoia_column, :paranoia_sentinel_value
|
|
182
|
+
|
|
183
|
+
self.paranoia_column = (options[:column] || :deleted_at).to_s
|
|
184
|
+
self.paranoia_sentinel_value = options.fetch(:sentinel_value) { Paranoia.default_sentinel_value }
|
|
185
|
+
default_scope { where(table_name => { paranoia_column => paranoia_sentinel_value }) }
|
|
186
|
+
|
|
187
|
+
before_restore {
|
|
188
|
+
self.class.notify_observers(:before_restore, self) if self.class.respond_to?(:notify_observers)
|
|
189
|
+
}
|
|
190
|
+
after_restore {
|
|
191
|
+
self.class.notify_observers(:after_restore, self) if self.class.respond_to?(:notify_observers)
|
|
192
|
+
}
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Please do not use this method in production.
|
|
196
|
+
# Pretty please.
|
|
197
|
+
def self.I_AM_THE_DESTROYER!
|
|
198
|
+
# TODO: actually implement spelling error fixes
|
|
199
|
+
puts %Q{
|
|
200
|
+
Sharon: "There should be a method called I_AM_THE_DESTROYER!"
|
|
201
|
+
Ryan: "What should this method do?"
|
|
202
|
+
Sharon: "It should fix all the spelling errors on the page!"
|
|
203
|
+
}
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def self.paranoid? ; false ; end
|
|
207
|
+
def paranoid? ; self.class.paranoid? ; end
|
|
208
|
+
|
|
209
|
+
# Override the persisted method to allow for the paranoia gem.
|
|
210
|
+
# If a paranoid record is selected, then we only want to check
|
|
211
|
+
# if it's a new record, not if it is "destroyed".
|
|
212
|
+
def persisted?
|
|
213
|
+
paranoid? ? !new_record? : super
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
private
|
|
217
|
+
|
|
218
|
+
def paranoia_column
|
|
219
|
+
self.class.paranoia_column
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def paranoia_sentinel_value
|
|
223
|
+
self.class.paranoia_sentinel_value
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
require 'paranoia/rspec' if defined? RSpec
|
data/paranoia.gemspec
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require File.expand_path("../lib/paranoia/version", __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
s.name = "cmoran92-paranoia"
|
|
6
|
+
s.version = Paranoia::VERSION
|
|
7
|
+
s.platform = Gem::Platform::RUBY
|
|
8
|
+
s.authors = ["radarlistener@gmail.com"]
|
|
9
|
+
s.email = []
|
|
10
|
+
s.homepage = "http://rubygems.org/gems/paranoia"
|
|
11
|
+
s.summary = "Paranoia is a re-implementation of acts_as_paranoid for Rails 3, using much, much, much less code."
|
|
12
|
+
s.description = "Paranoia is a re-implementation of acts_as_paranoid for Rails 3, using much, much, much less code. You would use either plugin / gem if you wished that when you called destroy on an Active Record object that it didn't actually destroy it, but just \"hid\" the record. Paranoia does this by setting a deleted_at field to the current time when you destroy a record, and hides it by scoping all queries on your model to only include records which do not have a deleted_at field."
|
|
13
|
+
|
|
14
|
+
s.required_rubygems_version = ">= 1.3.6"
|
|
15
|
+
s.rubyforge_project = "paranoia"
|
|
16
|
+
|
|
17
|
+
s.add_dependency "activerecord", "~> 4.0"
|
|
18
|
+
|
|
19
|
+
s.add_development_dependency "bundler", ">= 1.0.0"
|
|
20
|
+
s.add_development_dependency "rake"
|
|
21
|
+
|
|
22
|
+
s.files = `git ls-files`.split("\n")
|
|
23
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
|
24
|
+
s.require_path = 'lib'
|
|
25
|
+
end
|