on_destroy 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +62 -0
- data/Rakefile +11 -0
- data/lib/on_destroy/config.rb +20 -0
- data/lib/on_destroy/model.rb +81 -0
- data/lib/on_destroy/railtie.rb +12 -0
- data/lib/on_destroy/version.rb +3 -0
- data/lib/on_destroy.rb +4 -0
- metadata +69 -0
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
on_destroy
|
2
|
+
=====
|
3
|
+
|
4
|
+
This is a Rails 3.x ActiveRecord enhancement that allows you to:
|
5
|
+
* use `:do_not_delete` option to not call the delete callback on destroy by sending an empty block to `run_callbacks(:destroy)`.
|
6
|
+
* use `:set_column` to specify the column to update.
|
7
|
+
* use `:to` to specify the value to set the column to.
|
8
|
+
|
9
|
+
So, basically it will let you update a column/attribute of a model without actually deleting the record.
|
10
|
+
|
11
|
+
Also take a look at [acts_as_paranoid][acts_as_paranoid] [rails3_acts_as_paranoid][rails3_acts_as_paranoid], [soft_destroyable][soft_destroyable], [paranoia][paranoia], and other similar gems to be sure this is what you are looking for. The difference is that this gem does nothing with scoping, it just lets you mark a record as deleted without deleting it when you call destroy. This is just meant to provide a shortcut and slight safeguard in the situations where you want the client side to do the filtering of deleted records so that you can retain references to old models and maybe just color them differently in the UI to indicate that they are no longer active.
|
12
|
+
|
13
|
+
Add to your Gemfile:
|
14
|
+
|
15
|
+
gem 'on_destroy'
|
16
|
+
|
17
|
+
Then run:
|
18
|
+
|
19
|
+
bundle install
|
20
|
+
|
21
|
+
In your model you could include one of the following. You must ensure that the column exists and supports the value you are trying to set on it:
|
22
|
+
|
23
|
+
on_destroy :do_not_delete, set: :some_column, to: 'some string value'
|
24
|
+
on_destroy :do_not_delete, set: :some_column, to: nil
|
25
|
+
on_destroy :do_not_delete, set: :some_column, to: false
|
26
|
+
on_destroy :do_not_delete, set: :some_column, to: 1
|
27
|
+
on_destroy :do_not_delete, set: :some_column, to: lambda {Time.now}
|
28
|
+
|
29
|
+
Something similar to light version of rails3_acts_as_paranoid could be produced by the following (note: default_scope is not implemented or affected by this plugin, I'm just using it for an example):
|
30
|
+
|
31
|
+
default_scope where("deleted_at IS NOT NULL")
|
32
|
+
on_destroy :do_not_delete, set: :deleted_at, to: lambda {Time.now}
|
33
|
+
|
34
|
+
Do on_destroy for all models with:
|
35
|
+
|
36
|
+
# Do it for everything
|
37
|
+
OnDestroy.configure do
|
38
|
+
self.do_not_delete = true
|
39
|
+
self.set = [:deleted]
|
40
|
+
self.to = true
|
41
|
+
end
|
42
|
+
|
43
|
+
If you want control over how it intuits how something is deleted (which is to look at the deleted date) use `:is_deleted_if` which can be a value, nil, or a Proc that takes the attribute value:
|
44
|
+
|
45
|
+
on_destroy :do_not_delete, set: :some_column, to: lambda {Time.now}, is_deleted_if: {|c|Time.now > c} # provide time-travel resistent behavior of destroyed?/deleted?
|
46
|
+
on_destroy :do_not_delete, set: :some_column, to: 1 is_deleted_if: 1 # this is not necessary, as it will already check for 1 since you specified it in the :to
|
47
|
+
|
48
|
+
If you use a proc to set the value and a value of nil indicates that it should be deleted (which is kind of wierd), you'll need to set:
|
49
|
+
|
50
|
+
on_destroy :do_not_delete, set: :some_column, to: lambda {nil} is_deleted_if: nil
|
51
|
+
|
52
|
+
To call a normal-ish `destroy` method, use the `really_destroy` method. I think this is better than using `destroy!` because all of the other bang methods on ActiveRecord.base tend to just throw errors, not behave that differently, despite the `destroy!` method being a naming convention from acts_as_paranoid.
|
53
|
+
|
54
|
+
### License
|
55
|
+
|
56
|
+
Copyright (c) 2012 Gary S. Weaver, released under the [MIT license][lic].
|
57
|
+
|
58
|
+
[paranoia]: https://github.com/radar/paranoia
|
59
|
+
[soft_destroyable]: https://github.com/rockrep/soft_destroyable
|
60
|
+
[acts_as_paranoid]: http://github.com/technoweenie/acts_as_paranoid
|
61
|
+
[rails3_acts_as_paranoid]: https://github.com/goncalossilva/rails3_acts_as_paranoid
|
62
|
+
[lic]: http://github.com/garysweaver/on_destroy/blob/master/LICENSE
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
#http://nicksda.apotomo.de/2010/10/testing-your-rails-3-engine-sitting-in-a-gem/
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
5
|
+
t.libs << 'test'
|
6
|
+
t.test_files = FileList['test/**/*_test.rb']
|
7
|
+
t.verbose = true
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Run tests"
|
11
|
+
task :default => :test
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module OnDestroy
|
2
|
+
OPTIONS = [
|
3
|
+
:do_not_delete,
|
4
|
+
:set,
|
5
|
+
:to,
|
6
|
+
:is_deleted_if
|
7
|
+
]
|
8
|
+
|
9
|
+
class << self
|
10
|
+
OPTIONS.each{|o|attr_accessor o; define_method("#{o}?".to_sym){!!send("#{o}")}}
|
11
|
+
def configure(&blk); class_eval(&blk); end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Do it for everything
|
16
|
+
#OnDestroy.configure do
|
17
|
+
# self.do_not_delete = true
|
18
|
+
# self.set = [:deleted]
|
19
|
+
# self.to = true
|
20
|
+
#end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module OnDestroy
|
2
|
+
module Model
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :defined_is_deleted_if
|
7
|
+
# use values from config
|
8
|
+
OnDestroy::OPTIONS.each do |key|
|
9
|
+
class_attribute key, instance_writer: true
|
10
|
+
self.send("#{key}=".to_sym, OnDestroy.send(key))
|
11
|
+
end
|
12
|
+
around_destroy :do_on_destroy
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
# a shortcut to set configuration:
|
17
|
+
# self.do_not_delete, self.set, self.to, self.is_deleted_if
|
18
|
+
# and to default self.is_deleted_if to a proc that
|
19
|
+
def on_destroy(*args)
|
20
|
+
options = args.extract_options!
|
21
|
+
self.do_not_delete = true if args.include?(:do_not_delete)
|
22
|
+
self.set = options[:set] if options[:set]
|
23
|
+
self.to = options[:to] if options[:to]
|
24
|
+
if options[:is_deleted_if]
|
25
|
+
# set defined_is_deleted_if to allow explicit set to nil
|
26
|
+
self.defined_is_deleted_if = true
|
27
|
+
self.is_deleted_if = options[:is_deleted_if]
|
28
|
+
elsif (options[:to].is_a?(Proc))
|
29
|
+
# if :to is a Proc, assume that a nil value means it is not deleted and if not-nil is deleted.
|
30
|
+
# that is just a guess, based on the mark with deleted_at date example.
|
31
|
+
self.is_deleted_if = Proc.new {|v| v != nil}
|
32
|
+
else
|
33
|
+
self.is_deleted_if = Proc.new {|v| v == send(options[:to])}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Instance methods
|
39
|
+
|
40
|
+
# if self.set then will use update_attributes! to set the self.set attribute to self.to or self.to.call if it is a Proc.
|
41
|
+
def do_on_destroy
|
42
|
+
if self.set
|
43
|
+
to_value = self.to.is_a?(Proc) ? self.to.call : self.to
|
44
|
+
update_attributes! self.set => to_value
|
45
|
+
end
|
46
|
+
yield
|
47
|
+
end
|
48
|
+
|
49
|
+
# if self.do_not_delete? runs no/empty callback on :destroy, otherwise calls super.
|
50
|
+
def destroy
|
51
|
+
if self.do_not_delete?
|
52
|
+
# don't destroy
|
53
|
+
run_callbacks(:destroy) {}
|
54
|
+
else
|
55
|
+
# destroy
|
56
|
+
super
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# runs delete callback on :destroy
|
61
|
+
def really_destroy
|
62
|
+
run_callbacks(:destroy) {delete}
|
63
|
+
end
|
64
|
+
|
65
|
+
# if self.is_deleted_if is a Proc compares self.is_deleted_if.call to send(self.to).
|
66
|
+
# if self.is_deleted_if is not nil compares self.is_deleted_if.call to send(self.to).
|
67
|
+
# If self.is_deleted_if not a Proc, calls super.
|
68
|
+
def destroyed?
|
69
|
+
if self.is_deleted_if.is_a?(Proc)
|
70
|
+
self.is_deleted_if.call(send(self.to))
|
71
|
+
elsif self.is_deleted_if.nil? && !(self.defined_is_deleted_if == true)
|
72
|
+
# will default to super only if self.is_deleted_if not defined by user
|
73
|
+
super
|
74
|
+
else
|
75
|
+
self.is_deleted_if == send(self.to)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
alias_method :deleted?, :destroyed?
|
80
|
+
end
|
81
|
+
end
|
data/lib/on_destroy.rb
ADDED
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: on_destroy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Gary S. Weaver
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: Change ActiveModel's destroy behavior.
|
31
|
+
email:
|
32
|
+
- garysweaver@gmail.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- lib/on_destroy/config.rb
|
38
|
+
- lib/on_destroy/model.rb
|
39
|
+
- lib/on_destroy/railtie.rb
|
40
|
+
- lib/on_destroy/version.rb
|
41
|
+
- lib/on_destroy.rb
|
42
|
+
- Rakefile
|
43
|
+
- README.md
|
44
|
+
homepage: https://github.com/garysweaver/on_destroy
|
45
|
+
licenses:
|
46
|
+
- MIT
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
requirements: []
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.8.24
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Change destroy's behavior.
|
69
|
+
test_files: []
|