acts_as_paranoid_boolean_column 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Gonçalo Silva
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,250 @@
1
+ # ActsAsParanoid
2
+
3
+ A simple plugin which hides records instead of deleting them, being able to recover them.
4
+
5
+ **This branch targets Rails 3.2.** If you're working with another version, switch to the corresponding branch.
6
+
7
+ ## Credits
8
+
9
+ This plugin was inspired by [acts_as_paranoid](http://github.com/technoweenie/acts_as_paranoid) and [acts_as_active](http://github.com/fernandoluizao/acts_as_active).
10
+
11
+ While porting it to Rails 3, I decided to apply the ideas behind those plugins to an unified solution while removing a **lot** of the complexity found in them. I eventually ended up writing a new plugin from scratch.
12
+
13
+ ## Usage
14
+
15
+ You can enable ActsAsParanoid like this:
16
+
17
+ ```ruby
18
+ class Paranoiac < ActiveRecord::Base
19
+ acts_as_paranoid
20
+ end
21
+ ```
22
+
23
+ ### Options
24
+
25
+ You can also specify the name of the column to store it's *deletion* and the type of data it holds:
26
+
27
+ - `:column => 'deleted_at'`
28
+ - `:column_type => 'time'`
29
+
30
+ The values shown are the defaults. While *column* can be anything (as long as it exists in your database), *type* is restricted to:
31
+
32
+ - `boolean`
33
+ - `time` or
34
+ - `string`
35
+
36
+ If your column type is a `string`, you can also specify which value to use when marking an object as deleted by passing `:deleted_value` (default is "deleted"). Any records with a non-matching value in this column will be treated normally (ie: not deleted).
37
+
38
+ ### Filtering
39
+
40
+ If a record is deleted by ActsAsParanoid, it won't be retrieved when accessing the database. So, `Paranoiac.all` will **not** include the deleted_records. if you want to access them, you have 2 choices:
41
+
42
+ ```ruby
43
+ Paranoiac.only_deleted # retrieves the deleted records
44
+ Paranoiac.with_deleted # retrieves all records, deleted or not
45
+ ```
46
+
47
+ When using the default `column_type` of `'time'`, the following extra scopes are provided:
48
+
49
+ ```ruby
50
+ time = Time.now
51
+
52
+ Paranoiac.deleted_after_time(time)
53
+ Paranoiac.deleted_before_time(time)
54
+
55
+ # Or roll it all up and get a nice window:
56
+ Paranoiac.deleted_inside_time_window(time, 2.minutes)
57
+ ```
58
+
59
+ ### Real deletion
60
+
61
+ In order to really delete a record, just use:
62
+
63
+ ```ruby
64
+ paranoiac.destroy!
65
+ Paranoiac.delete_all!(conditions)
66
+ ```
67
+
68
+ You can also permanently delete a record by calling `destroy` or `delete_all` on it **twice**. If a record was already deleted (hidden by ActsAsParanoid) and you delete it again, it will be removed from the database. Take this example:
69
+
70
+ ```ruby
71
+ p = Paranoiac.first
72
+ p.destroy # does NOT delete the first record, just hides it
73
+ Paranoiac.only_deleted.where(:id => p.id).destroy # deletes the first record from the database
74
+ ```
75
+
76
+ ### Recovery
77
+
78
+ Recovery is easy. Just invoke `recover` on it, like this:
79
+
80
+ ```ruby
81
+ Paranoiac.only_deleted.where("name = ?", "not dead yet").first.recover
82
+ ```
83
+
84
+ All associations marked as `:dependent => :destroy` are also recursively recovered. If you would like to disable this behavior, you can call `recover` with the `recursive` option:
85
+
86
+ ```ruby
87
+ Paranoiac.only_deleted.where("name = ?", "not dead yet").first.recover(:recursive => false)
88
+ ```
89
+
90
+ If you would like to change this default behavior for one model, you can use the `recover_dependent_associations` option
91
+
92
+ ```ruby
93
+ class Paranoiac < ActiveRecord::Base
94
+ acts_as_paranoid :recover_dependent_associations => false
95
+ end
96
+ ```
97
+
98
+ By default, dependent records will be recovered if they were deleted within 2 minutes of the object upon which they depend. This restores the objects to the state before the recursive deletion without restoring other objects that were deleted earlier. The behavior is only available when both parent and dependant are using timestamp fields to mark deletion, which is the default behavior. This window can be changed with the `dependent_recovery_window` option:
99
+
100
+ ```ruby
101
+ class Paranoiac < ActiveRecord::Base
102
+ acts_as_paranoid
103
+ has_many :paranoids, :dependent => :destroy
104
+ end
105
+
106
+ class Paranoid < ActiveRecord::Base
107
+ belongs_to :paranoic
108
+
109
+ # Paranoid objects will be recovered alongside Paranoic objects
110
+ # if they were deleted within 10 minutes of the Paranoic object
111
+ acts_as_paranoid :dependent_recovery_window => 10.minutes
112
+ end
113
+ ```
114
+
115
+ or in the recover statement
116
+
117
+ ```ruby
118
+ Paranoiac.only_deleted.where("name = ?", "not dead yet").first.recover(:recovery_window => 30.seconds)
119
+ ```
120
+
121
+ ### Validation
122
+ ActiveRecord's built-in uniqueness validation does not account for records deleted by ActsAsParanoid. If you want to check for uniqueness among non-deleted records only, use the macro `validates_as_paranoid` in your model. Then, instead of using `validates_uniqueness_of`, use `validates_uniqueness_of_without_deleted`. This will keep deleted records from counting against the uniqueness check.
123
+
124
+ ```ruby
125
+ class Paranoiac < ActiveRecord::Base
126
+ acts_as_paranoid
127
+ validates_as_paranoid
128
+ validates_uniqueness_of_without_deleted :name
129
+ end
130
+
131
+ p1 = Paranoiac.create(:name => 'foo')
132
+ p1.destroy
133
+
134
+ p2 = Paranoiac.new(:name => 'foo')
135
+ p2.valid? #=> true
136
+ p2.save
137
+
138
+ p1.recover #=> fails validation!
139
+ ```
140
+
141
+ ### Status
142
+ You can check the status of your paranoid objects with the `deleted?` helper
143
+
144
+ ```ruby
145
+ Paranoiac.create(:name => 'foo').destroy
146
+ Paranoiac.with_deleted.first.deleted? #=> true
147
+ ```
148
+
149
+ ### Scopes
150
+
151
+ As you've probably guessed, `with_deleted` and `only_deleted` are scopes. You can, however, chain them freely with other scopes you might have. This
152
+
153
+ ```ruby
154
+ Paranoiac.pretty.with_deleted
155
+ ```
156
+
157
+ is exactly the same as
158
+
159
+ ```ruby
160
+ Paranoiac.with_deleted.pretty
161
+ ```
162
+
163
+ You can work freely with scopes and it will just work:
164
+
165
+ ```ruby
166
+ class Paranoiac < ActiveRecord::Base
167
+ acts_as_paranoid
168
+ scope :pretty, where(:pretty => true)
169
+ end
170
+
171
+ Paranoiac.create(:pretty => true)
172
+
173
+ Paranoiac.pretty.count #=> 1
174
+ Paranoiac.only_deleted.count #=> 0
175
+ Paranoiac.pretty.only_deleted.count #=> 0
176
+
177
+ Paranoiac.first.destroy
178
+
179
+ Paranoiac.pretty.count #=> 0
180
+ Paranoiac.only_deleted.count #=> 1
181
+ Paranoiac.pretty.only_deleted.count #=> 1
182
+ ```
183
+
184
+ ### Associations
185
+
186
+ Associations are also supported. From the simplest behaviors you'd expect to more nifty things like the ones mentioned previously or the usage of the `:with_deleted` option with `belongs_to`
187
+
188
+ ```ruby
189
+ class Parent < ActiveRecord::Base
190
+ has_many :children, :class_name => "ParanoiacChild"
191
+ end
192
+
193
+ class ParanoiacChild < ActiveRecord::Base
194
+ belongs_to :parent
195
+ belongs_to :parent_including_deleted, :class_name => "Parent", :with_deleted => true
196
+ # You cannot name association *_with_deleted
197
+ end
198
+
199
+ parent = Parent.first
200
+ child = parent.children.create
201
+ parent.destroy
202
+
203
+ child.parent #=> nil
204
+ child.parent_including_deleted #=> Parent (it works!)
205
+ ```
206
+
207
+ ## Caveats
208
+
209
+ Watch out for these caveats:
210
+
211
+
212
+ - You cannot use scopes named `with_deleted` and `only_deleted`
213
+ - You cannot use scopes named `deleted_inside_time_window`, `deleted_before_time`, `deleted_after_time` **if** your paranoid column's type is `time`
214
+ - You cannot name association `*_with_deleted`
215
+ - `unscoped` will return all records, deleted or not
216
+
217
+ # Support
218
+
219
+ This gem supports the most recent versions of Rails and Ruby.
220
+
221
+ ## Rails
222
+
223
+ For Rails 3.2 check the README at the [rails3.2](https://github.com/goncalossilva/rails3_acts_as_paranoid/tree/rails3.2) branch and add this to your Gemfile:
224
+
225
+ gem "acts_as_paranoid", "~>0.4.0"
226
+
227
+ For Rails 3.1 check the README at the [rails3.1](https://github.com/goncalossilva/rails3_acts_as_paranoid/tree/rails3.1) branch and add this to your Gemfile:
228
+
229
+ gem "rails3_acts_as_paranoid", "~>0.1.4"
230
+
231
+ For Rails 3.0 check the README at the [rails3.0](https://github.com/goncalossilva/rails3_acts_as_paranoid/tree/rails3.0) branch and add this to your Gemfile:
232
+
233
+ gem "rails3_acts_as_paranoid", "~>0.0.9"
234
+
235
+
236
+ ## Ruby
237
+
238
+ This gem is tested on Ruby 1.9, JRuby and Rubinius (both in 1.9 mode). It *might* work fine in 1.8, but it's not officially supported.
239
+
240
+ # Acknowledgements
241
+
242
+ * To [cheerfulstoic](https://github.com/cheerfulstoic) for adding recursive recovery
243
+ * To [Jonathan Vaught](https://github.com/gravelpup) for adding paranoid validations
244
+ * To [Geoffrey Hichborn](https://github.com/phene) for improving the overral code quality and adding support for after_commit
245
+ * To [flah00](https://github.com/flah00) for adding support for STI-based associations (with :dependent)
246
+ * To [vikramdhillon](https://github.com/vikramdhillon) for the idea and initial implementation of support for string column type
247
+ * To [Craig Walker](https://github.com/softcraft-development) for Rails 3.1 support and fixing various pending issues
248
+ * To [Charles G.](https://github.com/chuckg) for Rails 3.2 support and for making a desperately needed global code refactoring
249
+
250
+ Copyright © 2010 Gonçalo Silva, released under the MIT license
@@ -0,0 +1,34 @@
1
+ module ActsAsParanoid
2
+ module Associations
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ class << base
6
+ alias_method_chain :belongs_to, :deleted
7
+ end
8
+ end
9
+
10
+ module ClassMethods
11
+ def belongs_to_with_deleted(target, options = {})
12
+ with_deleted = options.delete(:with_deleted)
13
+ result = belongs_to_without_deleted(target, options)
14
+
15
+ if with_deleted
16
+ result.options[:with_deleted] = with_deleted
17
+ unless method_defined? "#{target}_with_unscoped"
18
+ class_eval <<-RUBY, __FILE__, __LINE__
19
+ def #{target}_with_unscoped(*args)
20
+ association = association(:#{target})
21
+ return nil if association.options[:polymorphic] && association.klass.nil?
22
+ return #{target}_without_unscoped(*args) unless association.klass.paranoid?
23
+ association.klass.with_deleted.scoping { #{target}_without_unscoped(*args) }
24
+ end
25
+ alias_method_chain :#{target}, :unscoped
26
+ RUBY
27
+ end
28
+ end
29
+
30
+ result
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,190 @@
1
+ module ActsAsParanoid
2
+ module Core
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def self.extended(base)
9
+ base.define_callbacks :recover
10
+ end
11
+
12
+ def before_recover(method)
13
+ set_callback :recover, :before, method
14
+ end
15
+
16
+ def after_recover(method)
17
+ set_callback :recover, :after, method
18
+ end
19
+
20
+ def with_deleted
21
+ without_paranoid_default_scope
22
+ end
23
+
24
+ def only_deleted
25
+ _is_not = string_type_with_deleted_value? ? "" : " NOT "
26
+ without_paranoid_default_scope.where("#{paranoid_column_reference} IS #{_is_not} ?", paranoid_configuration[:deleted_value])
27
+ end
28
+
29
+ def delete_all!(conditions = nil)
30
+ without_paranoid_default_scope.delete_all!(conditions)
31
+ end
32
+
33
+ def delete_all(conditions = nil)
34
+ update_all ["#{paranoid_configuration[:column]} = ?", delete_now_value], conditions
35
+ end
36
+
37
+ def paranoid_default_scope_sql
38
+ if string_type_with_deleted_value?
39
+ self.scoped.table[paranoid_column].eq(nil).or(self.scoped.table[paranoid_column].not_eq(paranoid_configuration[:deleted_value])).to_sql
40
+ else
41
+ self.scoped.table[paranoid_column].eq(paranoid_configuration[:deleted_value]).to_sql
42
+ end
43
+ end
44
+
45
+ def string_type_with_deleted_value?
46
+ (paranoid_column_type == :string) && !paranoid_configuration[:deleted_value].nil?
47
+ end
48
+
49
+ def column_type_with_deleted_value?
50
+ [:string, :boolean].include?(paranoid_column_type) && !paranoid_configuration[:deleted_value].nil?
51
+ end
52
+
53
+ def paranoid_column
54
+ paranoid_configuration[:column].to_sym
55
+ end
56
+
57
+ def paranoid_column_type
58
+ paranoid_configuration[:column_type].to_sym
59
+ end
60
+
61
+ def dependent_associations
62
+ self.reflect_on_all_associations.select {|a| [:destroy, :delete_all].include?(a.options[:dependent]) }
63
+ end
64
+
65
+ def delete_now_value
66
+ case paranoid_configuration[:column_type]
67
+ when "time" then Time.now
68
+ when "boolean" then true
69
+ when "string" then paranoid_configuration[:deleted_value]
70
+ end
71
+ end
72
+
73
+ protected
74
+
75
+ def without_paranoid_default_scope
76
+ scope = self.scoped.with_default_scope
77
+ scope.where_values.delete(paranoid_default_scope_sql)
78
+
79
+ scope
80
+ end
81
+ end
82
+
83
+ def persisted?
84
+ !(new_record? || @destroyed)
85
+ end
86
+
87
+ def paranoid_value
88
+ self.send(self.class.paranoid_column)
89
+ end
90
+
91
+ def destroy!
92
+ with_transaction_returning_status do
93
+ run_callbacks :destroy do
94
+ destroy_dependent_associations!
95
+ # Handle composite keys, otherwise we would just use `self.class.primary_key.to_sym => self.id`.
96
+ self.class.delete_all!(Hash[[Array(self.class.primary_key), Array(self.id)].transpose]) if persisted?
97
+ self.paranoid_value = self.class.delete_now_value
98
+ freeze
99
+ end
100
+ end
101
+ end
102
+
103
+ def destroy
104
+ if !deleted?
105
+ with_transaction_returning_status do
106
+ run_callbacks :destroy do
107
+ # Handle composite keys, otherwise we would just use `self.class.primary_key.to_sym => self.id`.
108
+ self.class.delete_all(Hash[[Array(self.class.primary_key), Array(self.id)].transpose]) if persisted?
109
+ self.paranoid_value = self.class.delete_now_value
110
+ self
111
+ end
112
+ end
113
+ else
114
+ destroy!
115
+ end
116
+ end
117
+
118
+ def recover(options={})
119
+ options = {
120
+ :recursive => self.class.paranoid_configuration[:recover_dependent_associations],
121
+ :recovery_window => self.class.paranoid_configuration[:dependent_recovery_window]
122
+ }.merge(options)
123
+
124
+ self.class.transaction do
125
+ run_callbacks :recover do
126
+ recover_dependent_associations(options[:recovery_window], options) if options[:recursive]
127
+
128
+ self.paranoid_value = nil
129
+ self.save
130
+ end
131
+ end
132
+ end
133
+
134
+ def recover_dependent_associations(window, options)
135
+ self.class.dependent_associations.each do |reflection|
136
+ next unless reflection.klass.paranoid?
137
+
138
+ scope = reflection.klass.only_deleted
139
+
140
+ # Merge in the association's scope
141
+ scope = scope.merge(association(reflection.name).association_scope)
142
+
143
+ # We can only recover by window if both parent and dependant have a
144
+ # paranoid column type of :time.
145
+ if self.class.paranoid_column_type == :time && reflection.klass.paranoid_column_type == :time
146
+ scope = scope.merge(reflection.klass.deleted_inside_time_window(paranoid_value, window))
147
+ end
148
+
149
+ scope.each do |object|
150
+ object.recover(options)
151
+ end
152
+ end
153
+ end
154
+
155
+ def destroy_dependent_associations!
156
+ self.class.dependent_associations.each do |reflection|
157
+ next unless reflection.klass.paranoid?
158
+
159
+ scope = reflection.klass.only_deleted
160
+
161
+ # Merge in the association's scope
162
+ scope = scope.merge(association(reflection.name).association_scope)
163
+
164
+ scope.each do |object|
165
+ object.destroy!
166
+ end
167
+ end
168
+ end
169
+
170
+ def deleted?
171
+ return false if paranoid_value.nil?
172
+
173
+ if self.class.column_type_with_deleted_value?
174
+ paranoid_value == self.class.delete_now_value
175
+ else
176
+ return true
177
+ end
178
+ end
179
+
180
+ alias_method :destroyed?, :deleted?
181
+
182
+
183
+ private
184
+
185
+ def paranoid_value=(value)
186
+ self.send("#{self.class.paranoid_column}=", value)
187
+ end
188
+
189
+ end
190
+ end
@@ -0,0 +1,36 @@
1
+ module ActsAsParanoid
2
+ module Relation
3
+ def self.included(base)
4
+ base.class_eval do
5
+ def paranoid?
6
+ klass.try(:paranoid?) ? true : false
7
+ end
8
+
9
+ def paranoid_deletion_attributes
10
+ { klass.paranoid_column => klass.delete_now_value }
11
+ end
12
+
13
+ alias_method :orig_delete_all, :delete_all
14
+ def delete_all!(conditions = nil)
15
+ if conditions
16
+ where(conditions).delete_all!
17
+ else
18
+ orig_delete_all
19
+ end
20
+ end
21
+
22
+ def delete_all(conditions = nil)
23
+ if paranoid?
24
+ update_all(paranoid_deletion_attributes, conditions)
25
+ else
26
+ delete_all!(conditions)
27
+ end
28
+ end
29
+
30
+ def destroy!(id_or_array)
31
+ where(primary_key => id_or_array).orig_delete_all
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,43 @@
1
+ require 'active_support/core_ext/array/wrap'
2
+
3
+ module ActsAsParanoid
4
+ module Validations
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ class UniquenessWithoutDeletedValidator < ActiveRecord::Validations::UniquenessValidator
10
+ def validate_each(record, attribute, value)
11
+ finder_class = find_finder_class_for(record)
12
+ table = finder_class.arel_table
13
+
14
+ coder = record.class.serialized_attributes[attribute.to_s]
15
+
16
+ if value && coder
17
+ value = coder.dump value
18
+ end
19
+
20
+ relation = build_relation(finder_class, table, attribute, value)
21
+ [Array(finder_class.primary_key), Array(record.send(:id))].transpose.each do |pk_key, pk_value|
22
+ relation = relation.and(table[pk_key.to_sym].not_eq(pk_value))
23
+ end if record.persisted?
24
+
25
+ Array.wrap(options[:scope]).each do |scope_item|
26
+ scope_value = record.send(scope_item)
27
+ relation = relation.and(table[scope_item].eq(scope_value))
28
+ end
29
+
30
+ # Re-add ActsAsParanoid default scope conditions manually.
31
+ if finder_class.unscoped.where(finder_class.paranoid_default_scope_sql).where(relation).exists?
32
+ record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
33
+ end
34
+ end
35
+ end
36
+
37
+ module ClassMethods
38
+ def validates_uniqueness_of_without_deleted(*attr_names)
39
+ validates_with UniquenessWithoutDeletedValidator, _merge_attributes(attr_names)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,75 @@
1
+ require 'active_record/base'
2
+ require 'active_record/relation'
3
+ require 'active_record/callbacks'
4
+ require 'acts_as_paranoid/core'
5
+ require 'acts_as_paranoid/associations'
6
+ require 'acts_as_paranoid/validations'
7
+ require 'acts_as_paranoid/relation'
8
+
9
+
10
+ module ActsAsParanoid
11
+
12
+ def paranoid?
13
+ self.included_modules.include?(ActsAsParanoid::Core)
14
+ end
15
+
16
+ def validates_as_paranoid
17
+ include ActsAsParanoid::Validations
18
+ end
19
+
20
+ def acts_as_paranoid(options = {})
21
+ raise ArgumentError, "Hash expected, got #{options.class.name}" if not options.is_a?(Hash) and not options.empty?
22
+
23
+ class_attribute :paranoid_configuration, :paranoid_column_reference
24
+
25
+ self.paranoid_configuration = { :column => "deleted_at", :column_type => "time", :recover_dependent_associations => true, :dependent_recovery_window => 2.minutes }
26
+ self.paranoid_configuration.merge!({ :deleted_value => "deleted" }) if options[:column_type] == "string"
27
+ self.paranoid_configuration.merge!(options) # user options
28
+
29
+ raise ArgumentError, "'time', 'boolean' or 'string' expected for :column_type option, got #{paranoid_configuration[:column_type]}" unless ['time', 'boolean', 'string'].include? paranoid_configuration[:column_type]
30
+
31
+ self.paranoid_column_reference = "#{self.table_name}.#{paranoid_configuration[:column]}"
32
+
33
+ return if paranoid?
34
+
35
+ include ActsAsParanoid::Core
36
+
37
+ # Magic!
38
+ default_scope do
39
+ # lazy load self.columns
40
+ if (self.paranoid_configuration[:column_type] == "boolean") && (self.columns.detect {|column| column.name == self.paranoid_configuration[:column] }.default === false)
41
+ self.paranoid_configuration.merge!({:deleted_value => false})
42
+ end
43
+ where(paranoid_default_scope_sql)
44
+ end
45
+
46
+ # The paranoid column should not be mass-assignable
47
+ attr_protected paranoid_configuration[:column]
48
+
49
+ # The paranoid column should not be mass-assignable
50
+ attr_protected paranoid_configuration[:column]
51
+
52
+ if paranoid_configuration[:column_type] == 'time'
53
+ scope :deleted_inside_time_window, lambda {|time, window|
54
+ deleted_after_time((time - window)).deleted_before_time((time + window))
55
+ }
56
+
57
+ scope :deleted_after_time, lambda { |time| where("#{paranoid_column} > ?", time) }
58
+ scope :deleted_before_time, lambda { |time| where("#{paranoid_column} < ?", time) }
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+
65
+ # Extend ActiveRecord's functionality
66
+ ActiveRecord::Base.send :extend, ActsAsParanoid
67
+
68
+ # Extend ActiveRecord::Base with paranoid associations
69
+ ActiveRecord::Base.send :include, ActsAsParanoid::Associations
70
+
71
+ # Override ActiveRecord::Relation's behavior
72
+ ActiveRecord::Relation.send :include, ActsAsParanoid::Relation
73
+
74
+ # Push the recover callback onto the activerecord callback list
75
+ ActiveRecord::Callbacks::CALLBACKS.push(:before_recover, :after_recover)
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_paranoid_boolean_column
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Goncalo Silva
9
+ - Charles G.
10
+ - Rick Olson
11
+ - mvj3
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+ date: 2013-06-17 00:00:00.000000000 Z
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: activerecord
19
+ requirement: !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: '3.2'
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '3.2'
33
+ description: Active Record (~>3.2) plugin which allows you to hide and restore records
34
+ without actually deleting them. Check its GitHub page for more in-depth information.
35
+ email:
36
+ - mvjome@gmail.com
37
+ executables: []
38
+ extensions: []
39
+ extra_rdoc_files: []
40
+ files:
41
+ - lib/acts_as_paranoid/associations.rb
42
+ - lib/acts_as_paranoid/core.rb
43
+ - lib/acts_as_paranoid/relation.rb
44
+ - lib/acts_as_paranoid/validations.rb
45
+ - lib/acts_as_paranoid.rb
46
+ - LICENSE
47
+ - README.markdown
48
+ homepage: https://github.com/mvj3/rails3_acts_as_paranoid
49
+ licenses: []
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: 1.3.6
66
+ requirements: []
67
+ rubyforge_project: acts_as_paranoid_boolean_column
68
+ rubygems_version: 1.8.25
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Active Record (~>3.2) plugin which allows you to hide and restore records
72
+ without actually deleting them.
73
+ test_files: []