gravelpup-rails3_acts_as_paranoid 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.markdown +56 -0
- data/lib/rails3_acts_as_paranoid.rb +71 -0
- data/lib/validations/uniqueness_without_deleted.rb +38 -0
- metadata +85 -0
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,56 @@
|
|
1
|
+
# ActsAsParanoid
|
2
|
+
|
3
|
+
A simple plugin which hides records instead of deleting them, being able to recover them.
|
4
|
+
|
5
|
+
## Credits
|
6
|
+
|
7
|
+
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).
|
8
|
+
|
9
|
+
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.
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
You can enable ActsAsParanoid like this:
|
14
|
+
|
15
|
+
class Paranoiac < ActiveRecord::Base
|
16
|
+
acts_as_paranoid
|
17
|
+
end
|
18
|
+
|
19
|
+
### Options
|
20
|
+
|
21
|
+
You can also specify the name of the column to store it's *deletion* and the type of data it holds:
|
22
|
+
|
23
|
+
- :column => 'deleted_at'
|
24
|
+
- :type => 'time'
|
25
|
+
|
26
|
+
The values shown are the defaults. While *column* can be anything (as long as it exists in your database), *type* is restricted to "boolean" or "time".
|
27
|
+
|
28
|
+
### Filtering
|
29
|
+
|
30
|
+
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:
|
31
|
+
Paranoiac.only_deleted # retrieves the deleted records
|
32
|
+
Paranoiac.with_deleted # retrieves all records, deleted or not
|
33
|
+
|
34
|
+
### Real deletion
|
35
|
+
|
36
|
+
In order to really delete a record, just use:
|
37
|
+
paranoiac.destroy!
|
38
|
+
Paranoiac.delete_all!(conditions)
|
39
|
+
|
40
|
+
You can also definitively 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:
|
41
|
+
Paranoiac.first.destroy # does NOT delete the first record, just hides it
|
42
|
+
Paranoiac.only_deleted.destroy # deletes the first record from the database
|
43
|
+
|
44
|
+
### Recovery
|
45
|
+
|
46
|
+
Recovery is easy. Just invoke `recover` on it, like this:
|
47
|
+
Paranoiac.only_deleted.where("name = ?", "not dead yet").first.recover
|
48
|
+
|
49
|
+
## Caveats
|
50
|
+
|
51
|
+
Watch out for these caveats:
|
52
|
+
|
53
|
+
- If you use default\_scope in your model, you need to include it after the `acts_as_paranoid` invocation
|
54
|
+
- You cannot use scopes named `with_deleted` and `only_deleted`
|
55
|
+
|
56
|
+
Copyright © 2010 Gonçalo Silva, released under the MIT license
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'validations/uniqueness_without_deleted'
|
3
|
+
|
4
|
+
module ActsAsParanoid
|
5
|
+
def acts_as_paranoid(options = {})
|
6
|
+
raise ArgumentError, "Hash expected, got #{options.class.name}" if not options.is_a?(Hash) and not options.empty?
|
7
|
+
|
8
|
+
configuration = { :column => "deleted_at", :column_type => "time" }
|
9
|
+
configuration.update(options) unless options.nil?
|
10
|
+
|
11
|
+
type = case configuration[:column_type]
|
12
|
+
when "time" then "Time.now"
|
13
|
+
when "boolean" then "true"
|
14
|
+
else
|
15
|
+
raise ArgumentError, "'time' or 'boolean' expected for :column_type option, got #{configuration[:column_type]}"
|
16
|
+
end
|
17
|
+
|
18
|
+
class_eval <<-EOV
|
19
|
+
default_scope where("#{self.table_name}.#{configuration[:column]} IS ?", nil)
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def with_deleted
|
23
|
+
self.unscoped.where("") #self.unscoped.reload
|
24
|
+
end
|
25
|
+
|
26
|
+
def only_deleted
|
27
|
+
self.unscoped.where("#{self.table_name}.#{configuration[:column]} IS NOT ?", nil)
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete_all!(conditions = nil)
|
31
|
+
self.unscoped.delete_all!(conditions)
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete_all(conditions = nil)
|
35
|
+
update_all ["#{configuration[:column]} = ?", #{type}], conditions
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def destroy!
|
40
|
+
before_destroy() if respond_to?(:before_destroy)
|
41
|
+
|
42
|
+
#{self.name}.delete_all!(:id => self)
|
43
|
+
|
44
|
+
after_destroy() if respond_to?(:after_destroy)
|
45
|
+
end
|
46
|
+
|
47
|
+
def destroy
|
48
|
+
run_callbacks :destroy do
|
49
|
+
if self.#{configuration[:column]} == nil
|
50
|
+
#{self.name}.delete_all(:id => self.id)
|
51
|
+
else
|
52
|
+
#{self.name}.delete_all!(:id => self.id)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def recover
|
58
|
+
self.update_attribute(:#{configuration[:column]}, nil)
|
59
|
+
end
|
60
|
+
|
61
|
+
ActiveRecord::Relation.class_eval do
|
62
|
+
alias_method :delete_all!, :delete_all
|
63
|
+
alias_method :destroy!, :destroy
|
64
|
+
end
|
65
|
+
EOV
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Extend ActiveRecord's functionality
|
70
|
+
ActiveRecord::Base.send :extend, ActsAsParanoid
|
71
|
+
ActiveRecord::Base.send :extend, ParanoidValidations::ClassMethods
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'active_support/core_ext/array/wrap'
|
2
|
+
|
3
|
+
module ParanoidValidations
|
4
|
+
class UniquenessWithoutDeletedValidator < ActiveRecord::Validations::UniquenessValidator
|
5
|
+
def validate_each(record, attribute, value)
|
6
|
+
finder_class = find_finder_class_for(record)
|
7
|
+
|
8
|
+
if value && record.class.serialized_attributes.key?(attribute.to_s)
|
9
|
+
value = YAML.dump value
|
10
|
+
end
|
11
|
+
|
12
|
+
sql, params = mount_sql_and_params(finder_class, record.class.quoted_table_name, attribute, value)
|
13
|
+
|
14
|
+
# This is the only changed line from the base class version - it does finder_class.unscoped
|
15
|
+
relation = finder_class.where(sql, *params)
|
16
|
+
|
17
|
+
Array.wrap(options[:scope]).each do |scope_item|
|
18
|
+
scope_value = record.send(scope_item)
|
19
|
+
relation = relation.where(scope_item => scope_value)
|
20
|
+
end
|
21
|
+
|
22
|
+
if record.persisted?
|
23
|
+
# TODO : This should be in Arel
|
24
|
+
relation = relation.where("#{record.class.quoted_table_name}.#{record.class.primary_key} <> ?", record.send(:id))
|
25
|
+
end
|
26
|
+
|
27
|
+
if relation.exists?
|
28
|
+
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
def validates_uniqueness_of_without_deleted(*attr_names)
|
35
|
+
validates_with UniquenessWithoutDeletedValidator, _merge_attributes(attr_names)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gravelpup-rails3_acts_as_paranoid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 5
|
9
|
+
version: 0.0.5
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- "Gon\xC3\xA7alo Silva"
|
13
|
+
- Jonathan Vaught
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-12-08 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: activerecord
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
segments:
|
30
|
+
- 3
|
31
|
+
- 0
|
32
|
+
version: "3.0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: Active Record (>=3.0) plugin which allows you to hide and restore records without actually deleting them. Check its GitHub page for more in-depth information.
|
36
|
+
email:
|
37
|
+
- jonathan.vaught@gmail.com
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
files:
|
45
|
+
- lib/rails3_acts_as_paranoid.rb
|
46
|
+
- lib/validations/uniqueness_without_deleted.rb
|
47
|
+
- LICENSE
|
48
|
+
- README.markdown
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: http://github.com/gravelpup/rails3_acts_as_paranoid
|
51
|
+
licenses: []
|
52
|
+
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
- lib/validations
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
segments:
|
65
|
+
- 0
|
66
|
+
version: "0"
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 1
|
74
|
+
- 3
|
75
|
+
- 7
|
76
|
+
version: 1.3.7
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project: gravelpup-rails3_acts_as_paranoid
|
80
|
+
rubygems_version: 1.3.7
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: Active Record (>=3.0) plugin which allows you to hide and restore records without actually deleting them.
|
84
|
+
test_files: []
|
85
|
+
|