deactivatable 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  coverage
4
4
  rdoc
5
5
  pkg
6
+ .project
data/README.rdoc CHANGED
@@ -1,10 +1,25 @@
1
1
  = deactivatable
2
2
 
3
+ == Description
3
4
  Deactivatable provides methods and a default_scope to allow ActiveRecord objects to be deactivated instead of deleted.
4
5
  This is useful if an object needs to be removed from general use, but it's data needs to be retained.
5
6
  Additionally, Deactivatable provides the ability to specify dependencies which also need to be deactivated.
6
7
  Deactivation is determined by populating a deactivated_at field with the date time at which deactivation happened.
7
8
 
9
+ == Install
10
+ The deactivatable gem is hosted on GemCutter (http://gemcutter.org)
11
+ gem install deactivatable
12
+ OR
13
+ config.gem 'deactivatable', :source => 'http://gemcutter.org'
14
+
15
+ == Usage
16
+ * Add a deactivated_at datetime field to any table you want to be deactivatable
17
+ add_column :table_name, :deactivated_at, :datetime
18
+ * Add the acts_as_deactivatable call to any class that should be deactivatable
19
+ Options
20
+ :dependencies - A list of symbols specifying any associations that are also deactivatable. (The dependent association must separately be defined with acts_as_deactivatable).
21
+ :auto_configure_dependencies - true or false (default). If set to true, any association defined as :dependent => :destroy or :dependent => :delete_all will be added to the list of dependencies to deactivate. NOTE: This call must occur after your dependency definitions to work properly.
22
+
8
23
  == Note on Patches/Pull Requests
9
24
 
10
25
  * Fork the project.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
data/lib/deactivatable.rb CHANGED
@@ -11,7 +11,8 @@ module ActiveRecord
11
11
  # Define the calling class as being deactivatable.
12
12
  # A call to this will set the default scope of the object to look for deactivated_at = nil.
13
13
  # Options
14
- # *:dependencies* => A list of symbols specifying any associations that are also deactivatable. (This associations must separately be defined with acts_as_deactivatable).
14
+ # :dependencies - A list of symbols specifying any associations that are also deactivatable. (The dependent association must separately be defined with acts_as_deactivatable).
15
+ # :auto_configure_dependencies - true or false (default). If set to true, any association defined as :dependent => :destroy or :dependent => :delete_all will be added to the list of dependencies to deactivate. NOTE: This call must occur after your dependency definitions to work properly.
15
16
  #
16
17
  def acts_as_deactivatable(options={})
17
18
  extend ActiveRecord::Acts::Deactivatable::ClassMethods
@@ -20,6 +21,7 @@ module ActiveRecord
20
21
  default_scope :conditions => {:deactivated_at => nil}
21
22
 
22
23
  @deactivatable_options = options
24
+ setup_autoconfigured_dependencies if @deactivatable_options[:auto_configure_dependencies]
23
25
  end
24
26
 
25
27
  end
@@ -30,10 +32,6 @@ module ActiveRecord
30
32
  @deactivatable_options || {}
31
33
  end
32
34
 
33
- def deactivated_dependencies
34
- @deactivated_dependencies ||= []
35
- end
36
-
37
35
  # Yields to a block, executing that block after removing the deactivated_at scope.
38
36
  #
39
37
  def with_deactivated_objects_scope
@@ -43,8 +41,26 @@ module ActiveRecord
43
41
  end
44
42
  end
45
43
  end
44
+
45
+ private
46
+ # Scan the reflection associations defined on the current class,
47
+ # if the :dependent option is set to :destroy or :delete_all then add that reflection to the list of dependencies to be deactivated.
48
+ #
49
+ def setup_autoconfigured_dependencies
50
+ self.reflections.each_key { |reflection_name| setup_auto_configured_dependency(reflection_name) }
51
+ end
52
+
53
+ def setup_auto_configured_dependency(reflection_name)
54
+ @deactivatable_options[:dependencies] ||= []
55
+ reflection = self.reflections[reflection_name]
56
+
57
+ if [:destroy, :delete_all].include?(reflection.options[:dependent])
58
+ @deactivatable_options[:dependencies] << reflection_name
59
+ end
60
+ end
61
+
46
62
  end
47
-
63
+
48
64
  module InstanceMethods
49
65
 
50
66
  # Deactivate this object, and any associated objects as specified at definition time.
@@ -97,8 +113,9 @@ module ActiveRecord
97
113
  #
98
114
  def execute_on_dependency(dependency_name, method)
99
115
  self.class.reflections[dependency_name].klass.send(:with_exclusive_scope) do
100
- dependency = self.__send__(dependency_name)
101
- dependency.respond_to?(:map) ? dependency.map(&method) : dependency.__send__(method)
116
+ if dependency = self.__send__(dependency_name)
117
+ dependency.respond_to?(:map) ? dependency.map(&method) : dependency.__send__(method)
118
+ end
102
119
  end
103
120
  end
104
121
 
@@ -1,7 +1,6 @@
1
1
  class DeactivatableItem < ActiveRecord::Base
2
2
 
3
- has_many :deactivatable_dependencies
4
-
5
- acts_as_deactivatable :dependencies => [:deactivatable_dependencies]
3
+ acts_as_deactivatable
4
+
6
5
 
7
6
  end
@@ -2,6 +2,38 @@ require 'test_helper'
2
2
 
3
3
  class DeactivatableTest < Test::Unit::TestCase
4
4
 
5
+
6
+ def self.should_deactivate_and_reactivate_dependencies
7
+ context "on a call to deactivate!" do
8
+ setup do
9
+ @item.deactivate!
10
+ end
11
+
12
+ should "render dependency unfindable" do
13
+ @dependencies.each { |dependency| assert !DeactivatableDependency.exists?(dependency.id) }
14
+ end
15
+
16
+ should "set deactivate on dependency post" do
17
+ DeactivatableDependency.send(:with_exclusive_scope) do
18
+ @dependencies.map(&:reload)
19
+ @dependencies.each {|dependency| assert_not_nil(dependency.deactivated_at) }
20
+ end
21
+ end
22
+
23
+ context "when reactivated" do
24
+ setup do
25
+ @item.activate!
26
+ end
27
+
28
+ should "reactivate all dependencies" do
29
+ @dependencies.each { |dependency| assert(DeactivatableDependency.exists?(dependency.id)) }
30
+ end
31
+ end #when reactivated
32
+
33
+ end #on a call to deactivate!
34
+ end
35
+
36
+
5
37
  context "An inactive item, @item" do
6
38
  setup do
7
39
  @inactive_item = DeactivatableItem.new
@@ -57,38 +89,65 @@ class DeactivatableTest < Test::Unit::TestCase
57
89
 
58
90
  context "with dependencies, @dependencies" do
59
91
  setup do
60
- @dependencies = (0..5).map { DeactivatableDependency.new }
61
- @item.deactivatable_dependencies = @dependencies
92
+ @item.class.instance_eval { has_many :deactivatable_dependencies }
93
+ @item.class.instance_eval { acts_as_deactivatable :dependencies => [:deactivatable_dependencies] }
94
+ create_item_dependencies
62
95
  end
63
96
 
64
- context "on a call to deactivate!" do
65
- setup do
66
- @item.deactivate!
67
- end
68
-
69
- should "render dependency unfindable" do
70
- @dependencies.each { |dependency| assert !DeactivatableDependency.exists?(dependency.id) }
71
- end
72
-
73
- should "set deactivate on dependency post" do
74
- DeactivatableDependency.send(:with_exclusive_scope) do
75
- @dependencies.map(&:reload)
76
- @dependencies.each {|dependency| assert_not_nil(dependency.deactivated_at) }
77
- end
78
- end
79
-
80
- context "when reactivated" do
81
- setup do
82
- @item.activate!
83
- end
84
-
85
- should "reactivate all dependencies" do
86
- @dependencies.each { |dependency| assert(DeactivatableDependency.exists?(dependency.id)) }
87
- end
88
- end #when reactivated
89
-
90
- end #on a call to deactivate!
97
+ should_deactivate_and_reactivate_dependencies
91
98
  end #with dependencies, @dependencies
99
+
100
+ context "with dependencies, @dependencies, that are :dependent => :destroy, and with auto_configure_dependencies => true" do
101
+ setup do
102
+ @item.class.instance_eval { has_many :deactivatable_dependencies, :dependent => :destroy }
103
+ @item.class.instance_eval { acts_as_deactivatable :auto_configure_dependencies => true }
104
+ create_item_dependencies
105
+ end
106
+
107
+ should_deactivate_and_reactivate_dependencies
108
+ end #with dependencies, @dependencies, that are dependent destroy, and with auto_configure_dependencies => true
109
+
110
+ context "with dependencies, @dependencies, that are :dependent => :delete_all , and with auto_configure_dependencies => true" do
111
+ setup do
112
+ @item.class.instance_eval { has_many :deactivatable_dependencies, :dependent => :delete_all }
113
+ @item.class.instance_eval { acts_as_deactivatable :auto_configure_dependencies => true }
114
+ create_item_dependencies
115
+ end
116
+
117
+ should_deactivate_and_reactivate_dependencies
118
+ end #with dependencies, @dependencies, that are dependent destroy, and with auto_configure_dependencies => true
119
+
120
+ context "with a single dependency" do
121
+ setup do
122
+ @item.class.instance_eval { has_one :deactivatable_dependency }
123
+ @item.class.instance_eval { acts_as_deactivatable :dependencies => [:deactivatable_dependency] }
124
+ @dependency = DeactivatableDependency.new
125
+ @item.deactivatable_dependency = @dependency
126
+ @item.save!
127
+ @dependencies = [@dependency]
128
+ end
129
+
130
+ should_deactivate_and_reactivate_dependencies
131
+
132
+ context "that is nil" do
133
+ setup do
134
+ @item.deactivatable_dependency = nil
135
+ @item.save!
136
+ end
137
+
138
+
139
+ should "not raise an exception when deactivated" do
140
+ assert_nothing_raised { @item.deactivate! }
141
+ end
142
+ end #that is nil
143
+ end #with a single dependency
144
+
92
145
  end #An active item, @item
146
+
147
+ private
148
+ def create_item_dependencies
149
+ @dependencies = (0..5).map { DeactivatableDependency.new }
150
+ @item.deactivatable_dependencies = @dependencies
151
+ end
93
152
 
94
153
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deactivatable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Fitzgerald
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-06 00:00:00 -05:00
12
+ date: 2009-11-10 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency