purgatory 2.7.0 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.markdown +49 -0
- data/VERSION +1 -1
- data/lib/generators/purgatory/templates/create_purgatories.rb +1 -0
- data/lib/purgatory/active_record_descendant_attribute_accessors.rb +21 -0
- data/lib/purgatory/attribute_accessor_fields.rb +24 -0
- data/lib/purgatory/purgatory.rb +2 -0
- data/lib/purgatory/purgatory_module.rb +6 -2
- data/purgatory.gemspec +6 -3
- data/spec/purgatory_spec.rb +262 -1
- data/spec/support/active_record.rb +6 -0
- data/spec/support/item.rb +17 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
Y2M1NWE4MjU0ZDg0OWE0YTcwNzA3ZGMxYzAwM2U0MWE0ZTVlZTQ5NQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
OTEwZDI1MDM3YzhhMGFjNmYxM2RjMTk0NzFhOTY0MmZmMzI3ZjE5Yg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YjRmYTU3MGZhNzE1ZDZhZjQ0MDBlNWEwOTNmNThlZDU5YTVjYTVlOGUyZmQz
|
10
|
+
NGQzZTBiMTMyMzVkNDM5ZmM3NGUyMjU2OGJjOGJlNzEwMDVhMDQ2MWIyMmI5
|
11
|
+
NDc3ZTExY2I1NGU1MmI4ZjBjZThjM2M3M2MxMThhMDIzZDQ2Mzk=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZTdlZjc1NzlkZmMxYWY2Y2MyNzRhOTlhMTVmNGNhNDA5NTU2ZDIxZjIyOTU1
|
14
|
+
MmU1Yzc3YzdlYzEzNTc0MTY3NzdlNzhlMjlhY2Q1NGNiNjhmMDVhMGEzNDRi
|
15
|
+
ZDY1MTVjODRhYWUxMTY4MjFiZWM4YTBlNmQ2MjM3MjY1Njg3ZGY=
|
data/README.markdown
CHANGED
@@ -59,6 +59,55 @@ Here are some handy class and instance methods available to you:
|
|
59
59
|
purgatory.pending? # Returns true if the purgatory is pending, false otherwise
|
60
60
|
purgatory.approved? # Returns true if the purgatory has been approved, false otherwise
|
61
61
|
|
62
|
+
### ActiveRecord Lifecycle
|
63
|
+
|
64
|
+
When using purgatory, the timing of the activerecord lifecycle differs a bit. Normally when you run "ActiveRecord#save", the entire lifecycle of activerecord gets triggered by default. But when you replace "save" with "purgatory!", the callbacks woould only run until after_validation. It's only after you run "approve!" when the rest of callbacks (ie. before_save, after_create) gets triggered as well.
|
65
|
+
|
66
|
+
## Normal lifecycle
|
67
|
+
|
68
|
+
before_validation
|
69
|
+
after_validation
|
70
|
+
before_save
|
71
|
+
around_save
|
72
|
+
before_create
|
73
|
+
around_create
|
74
|
+
after_create
|
75
|
+
after_save
|
76
|
+
|
77
|
+
## Purgatory lifecycle
|
78
|
+
|
79
|
+
# purgatory!
|
80
|
+
before_validation
|
81
|
+
after_validation
|
82
|
+
|
83
|
+
# approve!
|
84
|
+
before_validation
|
85
|
+
after_validation
|
86
|
+
before_save
|
87
|
+
around_save
|
88
|
+
before_create
|
89
|
+
around_create
|
90
|
+
after_create
|
91
|
+
after_save
|
92
|
+
|
93
|
+
|
94
|
+
### Handling Virtual Attributes
|
95
|
+
|
96
|
+
Virtual attributes allow users store variables into active record objects temporarily without saving them into the database (usually created using attr_accessor). Because these attributes are sometimes being used even on later stages of activerecord lifecycle (i.e after_create, after_save), it's important that these virtual attributes continue to exist while using purgatory. If you're using purgatory, by default, these virtual attributes would only exist on "purgatory!" phase, and would get lost on the "approve!" phase. To make sure this doesn't happen, there are 2 ways of handling it.
|
97
|
+
|
98
|
+
1. Manual
|
99
|
+
|
100
|
+
use_purgatory :local_attributes => [:foo, :bar]
|
101
|
+
|
102
|
+
When you pass a hash that contains a list of virtual attributes that you want to save, purgatory will save the values of these attributes into the purgatory table during the "purgatory!" phase, so that when "approve!" is later called, the virtual attributes will be retrieved and will continue to be available in the remaining activerecord lifecyle.
|
103
|
+
|
104
|
+
2. Automatic
|
105
|
+
|
106
|
+
use_purgatory :local_attributes => :all
|
107
|
+
|
108
|
+
By specifying all, Purgatory will programmatically determine what the virtual attributes are and save them when "purgatory!" is called, so that they will be available during "approve!".
|
109
|
+
|
110
|
+
|
62
111
|
## Contributing to Purgatory
|
63
112
|
|
64
113
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.8.0
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveRecordDescendantAttributeAccessors
|
2
|
+
|
3
|
+
def self.attr_accessor_instance_variables(obj)
|
4
|
+
include_ancestor_methods = false
|
5
|
+
|
6
|
+
ancestors_before_active_record_base = obj.class.ancestors.take_while { |klass| klass != ActiveRecord::Base }
|
7
|
+
|
8
|
+
instance_methods_of_ancestors_before_active_record_base = ancestors_before_active_record_base
|
9
|
+
.map { |klass| klass.instance_methods(include_ancestor_methods) }
|
10
|
+
.flatten
|
11
|
+
|
12
|
+
setter_methods_of_ancestors_before_active_record_base = instance_methods_of_ancestors_before_active_record_base
|
13
|
+
.select { |meth| meth.to_s.last == '=' }
|
14
|
+
|
15
|
+
possible_instance_variables_from_setter_methods = setter_methods_of_ancestors_before_active_record_base
|
16
|
+
.map { |meth| meth.to_s.prepend('@').chop.to_sym }
|
17
|
+
|
18
|
+
obj.instance_variables & possible_instance_variables_from_setter_methods
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'active_support/core_ext/module/attribute_accessors.rb'
|
2
|
+
|
3
|
+
require 'purgatory/active_record_descendant_attribute_accessors'
|
4
|
+
|
5
|
+
module AttributeAccessorFields
|
6
|
+
|
7
|
+
mattr_accessor :local_attributes
|
8
|
+
|
9
|
+
def self.determine_attr_accessor_fields(obj)
|
10
|
+
variables = if @@local_attributes == :all
|
11
|
+
ActiveRecordDescendantAttributeAccessors.attr_accessor_instance_variables(obj)
|
12
|
+
else
|
13
|
+
Array(@@local_attributes).map { |attribute|
|
14
|
+
attribute.to_s.prepend('@').to_sym
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
variables.inject({}) do |hash,var|
|
19
|
+
hash[var] = obj.instance_variable_get(var)
|
20
|
+
hash
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/purgatory/purgatory.rb
CHANGED
@@ -10,6 +10,7 @@ class Purgatory < ActiveRecord::Base
|
|
10
10
|
validates :soul_type, presence: true
|
11
11
|
|
12
12
|
serialize :requested_changes
|
13
|
+
serialize :attr_accessor_fields
|
13
14
|
|
14
15
|
def self.pending
|
15
16
|
where(approved_at: nil)
|
@@ -38,6 +39,7 @@ class Purgatory < ActiveRecord::Base
|
|
38
39
|
def approve!(approver = nil)
|
39
40
|
return false if approved?
|
40
41
|
requested_changes.each{|k,v| soul.send(:write_attribute, k, v[1])}
|
42
|
+
attr_accessor_fields.each{|k,v| soul.instance_variable_set(k, v)}
|
41
43
|
if soul.save
|
42
44
|
self.approver = approver
|
43
45
|
self.approved_at = Time.now
|
@@ -1,8 +1,11 @@
|
|
1
|
+
require 'purgatory/attribute_accessor_fields'
|
2
|
+
|
1
3
|
module PurgatoryModule
|
2
4
|
extend ActiveSupport::Concern
|
3
5
|
|
4
6
|
module ClassMethods
|
5
|
-
def use_purgatory
|
7
|
+
def use_purgatory(options={})
|
8
|
+
AttributeAccessorFields.local_attributes = options[:local_attributes]
|
6
9
|
self.has_many :purgatories, as: :soul
|
7
10
|
end
|
8
11
|
end
|
@@ -10,7 +13,7 @@ module PurgatoryModule
|
|
10
13
|
def purgatory!(requester = nil, options = {})
|
11
14
|
return nil if self.invalid?
|
12
15
|
return nil if Purgatory.pending_with_matching_soul(self).any? && options[:fail_if_matching_soul]
|
13
|
-
Purgatory.create soul: self, requester: requester
|
16
|
+
Purgatory.create soul: self, requester: requester, attr_accessor_fields: AttributeAccessorFields.determine_attr_accessor_fields(self)
|
14
17
|
end
|
15
18
|
|
16
19
|
class Configuration
|
@@ -27,4 +30,5 @@ module PurgatoryModule
|
|
27
30
|
@_configuration ||= Configuration.new
|
28
31
|
end
|
29
32
|
end
|
33
|
+
|
30
34
|
end
|
data/purgatory.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: purgatory 2.
|
5
|
+
# stub: purgatory 2.8.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "purgatory"
|
9
|
-
s.version = "2.
|
9
|
+
s.version = "2.8.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.authors = ["Elan Dubrofsky"]
|
13
|
-
s.date = "2013-11-
|
13
|
+
s.date = "2013-11-28"
|
14
14
|
s.description = "Put your model changes in purgatory and allow them to remain lost souls until they are approved"
|
15
15
|
s.email = "elan.dubrofsky@gmail.com"
|
16
16
|
s.extra_rdoc_files = [
|
@@ -29,12 +29,15 @@ Gem::Specification.new do |s|
|
|
29
29
|
"lib/generators/purgatory/purgatory_generator.rb",
|
30
30
|
"lib/generators/purgatory/templates/create_purgatories.rb",
|
31
31
|
"lib/purgatory.rb",
|
32
|
+
"lib/purgatory/active_record_descendant_attribute_accessors.rb",
|
33
|
+
"lib/purgatory/attribute_accessor_fields.rb",
|
32
34
|
"lib/purgatory/purgatory.rb",
|
33
35
|
"lib/purgatory/purgatory_module.rb",
|
34
36
|
"purgatory.gemspec",
|
35
37
|
"spec/purgatory_spec.rb",
|
36
38
|
"spec/support/active_record.rb",
|
37
39
|
"spec/support/animal.rb",
|
40
|
+
"spec/support/item.rb",
|
38
41
|
"spec/support/user.rb",
|
39
42
|
"spec/support/widget.rb"
|
40
43
|
]
|
data/spec/purgatory_spec.rb
CHANGED
@@ -2,6 +2,7 @@ require 'support/active_record'
|
|
2
2
|
require 'support/widget'
|
3
3
|
require 'support/user'
|
4
4
|
require 'support/animal'
|
5
|
+
require 'support/item'
|
5
6
|
require 'purgatory/purgatory'
|
6
7
|
|
7
8
|
describe Purgatory do
|
@@ -68,6 +69,26 @@ describe Purgatory do
|
|
68
69
|
Purgatory.count.should == 2
|
69
70
|
end
|
70
71
|
end
|
72
|
+
|
73
|
+
context "valid changes with attr_accessor" do
|
74
|
+
before do
|
75
|
+
create_object_change_purgatory_with_attr_accessor
|
76
|
+
@item = Item.find(@item.id)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should not change the object" do
|
80
|
+
@item.name.should == 'foo'
|
81
|
+
@item.price.should == 100
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should not save attr_accessor variable of object" do
|
85
|
+
@item.dante.should == nil
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should store the attr_accessor variables in the Purgatory object" do
|
89
|
+
@purgatory.attr_accessor_fields.should == { :@dante => "inferno" }
|
90
|
+
end
|
91
|
+
end
|
71
92
|
|
72
93
|
it "should not allow invalid changes to be put into purgatory" do
|
73
94
|
widget = Widget.create name: 'foo'
|
@@ -140,6 +161,24 @@ describe Purgatory do
|
|
140
161
|
end
|
141
162
|
end
|
142
163
|
|
164
|
+
context "valid object with attr_accessor" do
|
165
|
+
before do
|
166
|
+
create_new_object_purgatory_with_attr_accessor
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should store the attr_accessor variables in the Purgatory object" do
|
170
|
+
@purgatory.attr_accessor_fields.should == { :@dante => "inferno" }
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should store the requester and requested changes" do
|
174
|
+
@purgatory.requester.should == user1
|
175
|
+
@purgatory.requested_changes['name'].first.should == nil
|
176
|
+
@purgatory.requested_changes['name'].last.should == 'foo'
|
177
|
+
@purgatory.requested_changes['price'].first.should == nil
|
178
|
+
@purgatory.requested_changes['price'].last.should == 100
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
143
182
|
it "should not allow invalid object creation to be put into purgatory" do
|
144
183
|
widget = Widget.new name: ''
|
145
184
|
widget.purgatory!(user1).should be_nil
|
@@ -175,6 +214,36 @@ describe Purgatory do
|
|
175
214
|
@purgatory.approve!(user2).should be_false
|
176
215
|
end
|
177
216
|
end
|
217
|
+
|
218
|
+
context "approving object change purgatory with attr_accessor" do
|
219
|
+
before do
|
220
|
+
create_object_change_purgatory_with_attr_accessor
|
221
|
+
@purgatory.approve!(user2)
|
222
|
+
@item = Item.find(@item.id)
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should apply the changes" do
|
226
|
+
@item.name.should == 'bar'
|
227
|
+
@item.price.should == 200
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should apply changes that depend on attr_accessor instance_variable" do
|
231
|
+
@item.original_name.should == "inferno"
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should mark purgatory as approved and store approver" do
|
235
|
+
@purgatory.approver.should == user2
|
236
|
+
@purgatory.should be_approved
|
237
|
+
@purgatory.should_not be_pending
|
238
|
+
Purgatory.pending.count.should be_zero
|
239
|
+
Purgatory.approved.count.should == 1
|
240
|
+
Purgatory.approved.first.should == @purgatory
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should fail if you try to approve again" do
|
244
|
+
@purgatory.approve!(user2).should be_false
|
245
|
+
end
|
246
|
+
end
|
178
247
|
|
179
248
|
context "approving new object creation" do
|
180
249
|
before do
|
@@ -217,7 +286,25 @@ describe Purgatory do
|
|
217
286
|
dog.original_name.should == 'doggy'
|
218
287
|
dog.price.should == Dog::DEFAULT_PRICE
|
219
288
|
end
|
289
|
+
end
|
290
|
+
|
291
|
+
context "approving new object creation with attr_accessor" do
|
292
|
+
before do
|
293
|
+
create_new_object_purgatory_with_attr_accessor
|
294
|
+
@purgatory.approve!(user2)
|
295
|
+
end
|
220
296
|
|
297
|
+
it "should create the new object and apply any callbacks" do
|
298
|
+
Item.count.should == 1
|
299
|
+
item = Item.first
|
300
|
+
item.name.should == 'foo'
|
301
|
+
item.price.should == 100
|
302
|
+
end
|
303
|
+
|
304
|
+
it "should apply changes that depend on attr_accessor instance_variable" do
|
305
|
+
Item.first.original_name.should == 'inferno'
|
306
|
+
end
|
307
|
+
|
221
308
|
it "should mark purgatory as approved and store approver" do
|
222
309
|
@purgatory.approver.should == user2
|
223
310
|
@purgatory.should be_approved
|
@@ -232,6 +319,161 @@ describe Purgatory do
|
|
232
319
|
end
|
233
320
|
end
|
234
321
|
end
|
322
|
+
|
323
|
+
describe "determine_attr_accessor_fields" do
|
324
|
+
before do
|
325
|
+
AttributeAccessorFields.local_attributes = nil
|
326
|
+
end
|
327
|
+
|
328
|
+
after do
|
329
|
+
AttributeAccessorFields.local_attributes = nil
|
330
|
+
end
|
331
|
+
|
332
|
+
context "obj has no attr_accessors" do
|
333
|
+
before do
|
334
|
+
@obj = Widget.new
|
335
|
+
end
|
336
|
+
|
337
|
+
it "should not contain any thing" do
|
338
|
+
AttributeAccessorFields.determine_attr_accessor_fields(@obj).should == {}
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
context "obj has attr_accessors" do
|
343
|
+
before do
|
344
|
+
klass = create_subclass_of(Widget)
|
345
|
+
klass.instance_eval { attr_accessor :dante, :minos, :charon }
|
346
|
+
|
347
|
+
@obj = klass.new
|
348
|
+
|
349
|
+
@obj.dante = "inferno"
|
350
|
+
@obj.minos = "inferno"
|
351
|
+
@obj.charon = "inferno"
|
352
|
+
end
|
353
|
+
|
354
|
+
context "local_attributes is empty" do
|
355
|
+
it "should not contain any attr_accessor values" do
|
356
|
+
AttributeAccessorFields.determine_attr_accessor_fields(@obj).should == {}
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
context "local_attributes is array" do
|
361
|
+
context "array size is 1" do
|
362
|
+
before do
|
363
|
+
AttributeAccessorFields.local_attributes = [:dante]
|
364
|
+
end
|
365
|
+
|
366
|
+
it "should only contain attr_accessors specified in array" do
|
367
|
+
AttributeAccessorFields.determine_attr_accessor_fields(@obj).should == { :@dante => "inferno" }
|
368
|
+
end
|
369
|
+
end
|
370
|
+
context "array size is more than 1" do
|
371
|
+
before do
|
372
|
+
AttributeAccessorFields.local_attributes = [:dante, :minos]
|
373
|
+
end
|
374
|
+
|
375
|
+
it "should only contain attr_accessors specified in array" do
|
376
|
+
AttributeAccessorFields.determine_attr_accessor_fields(@obj).should == { :@dante => "inferno", :@minos => "inferno" }
|
377
|
+
end
|
378
|
+
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
context "value of local_variables is :all" do
|
383
|
+
before do
|
384
|
+
AttributeAccessorFields.local_attributes = :all
|
385
|
+
end
|
386
|
+
|
387
|
+
it "should automatically determine attr_accessor values that doesnt include ones belonging to AR::Base and its ancestors, and then store these values" do
|
388
|
+
AttributeAccessorFields.determine_attr_accessor_fields(@obj).should == { :@dante => "inferno", :@minos => "inferno", :@charon => "inferno" }
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
describe "#attr_accessor_instance_variables" do
|
395
|
+
context "attr_accessor defined in a module/class that is an ancestor of ActiveRecord::Base" do
|
396
|
+
before do
|
397
|
+
@active_record_ancestor = ActiveRecord::Base.ancestors[1]
|
398
|
+
@active_record_ancestor.instance_eval { attr_accessor :dante }
|
399
|
+
@widget = Widget.new name: 'foo', price: 100
|
400
|
+
@widget.dante = "inferno"
|
401
|
+
end
|
402
|
+
|
403
|
+
after do
|
404
|
+
@active_record_ancestor.class_eval { undef :dante }
|
405
|
+
@active_record_ancestor.class_eval { undef :dante= }
|
406
|
+
end
|
407
|
+
|
408
|
+
it "should not include instance_variables that belong to ancestor of ActiveRecord::Base" do
|
409
|
+
ActiveRecordDescendantAttributeAccessors.attr_accessor_instance_variables(@widget).should == []
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
context "attr_accessor defined in ActiveRecord::Base" do
|
414
|
+
before do
|
415
|
+
ActiveRecord::Base.instance_eval { attr_accessor :dante }
|
416
|
+
@widget = Widget.new name: 'foo', price: 100
|
417
|
+
@widget.dante = "inferno"
|
418
|
+
end
|
419
|
+
|
420
|
+
after do
|
421
|
+
ActiveRecord::Base.class_eval { undef :dante }
|
422
|
+
ActiveRecord::Base.class_eval { undef :dante= }
|
423
|
+
end
|
424
|
+
|
425
|
+
it "should not include instance_variables that belong to ActiveRecord::Base" do
|
426
|
+
ActiveRecordDescendantAttributeAccessors.attr_accessor_instance_variables(@widget).should == []
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
context "attr_accessor defined in a module/class that is not an ancestor of ActiveRecord::Base" do
|
431
|
+
context "attr_accessor defined in a module mixin" do
|
432
|
+
before do
|
433
|
+
klass = create_subclass_of(Widget)
|
434
|
+
module A; attr_accessor :dante; end
|
435
|
+
klass.instance_eval { include A }
|
436
|
+
|
437
|
+
@widget = klass.new name: 'foo', price: 100
|
438
|
+
@widget.dante = "inferno"
|
439
|
+
end
|
440
|
+
|
441
|
+
it "should include instance_variables from attr_accessors that belong to descendant of ActiveRecord::Base" do
|
442
|
+
ActiveRecordDescendantAttributeAccessors.attr_accessor_instance_variables(@widget).should == [:@dante]
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
context "attr_accessor defined in a superclass" do
|
447
|
+
before do
|
448
|
+
klass = create_subclass_of(Widget)
|
449
|
+
subklass = create_subclass_of(klass)
|
450
|
+
|
451
|
+
klass.instance_eval { attr_accessor :dante }
|
452
|
+
|
453
|
+
@widget = subklass.new name: 'foo', price: 100
|
454
|
+
@widget.dante = "inferno"
|
455
|
+
end
|
456
|
+
|
457
|
+
it "should include instance_variables from attr_accessors that belong to descendant of ActiveRecord::Base" do
|
458
|
+
ActiveRecordDescendantAttributeAccessors.attr_accessor_instance_variables(@widget).should == [:@dante]
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
context "attr_accessor defined in a class" do
|
463
|
+
before do
|
464
|
+
klass = create_subclass_of(Widget)
|
465
|
+
klass.instance_eval { attr_accessor :dante }
|
466
|
+
|
467
|
+
@widget = klass.new name: 'foo', price: 100
|
468
|
+
@widget.dante = "inferno"
|
469
|
+
end
|
470
|
+
|
471
|
+
it "should include instance_variables from attr_accessors that belong to descendant of ActiveRecord::Base" do
|
472
|
+
ActiveRecordDescendantAttributeAccessors.attr_accessor_instance_variables(@widget).should == [:@dante]
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
235
477
|
|
236
478
|
private
|
237
479
|
|
@@ -243,7 +485,7 @@ describe Purgatory do
|
|
243
485
|
@purgatory = Purgatory.find(purgatory.id)
|
244
486
|
@widget.reload
|
245
487
|
end
|
246
|
-
|
488
|
+
|
247
489
|
def create_new_object_purgatory
|
248
490
|
widget = Widget.new name: 'foo', price: 100
|
249
491
|
purgatory = widget.purgatory! user1
|
@@ -256,4 +498,23 @@ describe Purgatory do
|
|
256
498
|
@purgatory = Purgatory.find(purgatory.id)
|
257
499
|
end
|
258
500
|
|
501
|
+
def create_object_change_purgatory_with_attr_accessor
|
502
|
+
@item = Item.create name: 'foo', price: 100, dante: "classic"
|
503
|
+
@item.name = 'bar'
|
504
|
+
@item.price = 200
|
505
|
+
@item.dante = "inferno"
|
506
|
+
purgatory = @item.purgatory! user1
|
507
|
+
@purgatory = Purgatory.find(purgatory.id)
|
508
|
+
@item.reload
|
509
|
+
end
|
510
|
+
|
511
|
+
def create_new_object_purgatory_with_attr_accessor
|
512
|
+
item = Item.new name: 'foo', price: 100, dante: "inferno"
|
513
|
+
purgatory = item.purgatory! user1
|
514
|
+
@purgatory = Purgatory.find(purgatory.id)
|
515
|
+
end
|
516
|
+
|
517
|
+
def create_subclass_of(klass)
|
518
|
+
Class.new(klass)
|
519
|
+
end
|
259
520
|
end
|
@@ -21,6 +21,12 @@ ActiveRecord::Migration.create_table :animals do |t|
|
|
21
21
|
t.string :type
|
22
22
|
t.integer :price
|
23
23
|
t.string :original_name
|
24
|
+
end
|
25
|
+
|
26
|
+
ActiveRecord::Migration.create_table :items do |t|
|
27
|
+
t.string :name
|
28
|
+
t.integer :price
|
29
|
+
t.string :original_name
|
24
30
|
t.timestamps
|
25
31
|
end
|
26
32
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'purgatory'
|
2
|
+
|
3
|
+
class Item < ActiveRecord::Base
|
4
|
+
use_purgatory local_attributes: [:dante]
|
5
|
+
|
6
|
+
validates :name, presence: true
|
7
|
+
|
8
|
+
attr_accessor :dante
|
9
|
+
|
10
|
+
after_save :set_original_name
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def set_original_name
|
15
|
+
update_column(:original_name, @dante)
|
16
|
+
end
|
17
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: purgatory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elan Dubrofsky
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
11
|
+
date: 2013-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rdoc
|
@@ -72,12 +72,15 @@ files:
|
|
72
72
|
- lib/generators/purgatory/purgatory_generator.rb
|
73
73
|
- lib/generators/purgatory/templates/create_purgatories.rb
|
74
74
|
- lib/purgatory.rb
|
75
|
+
- lib/purgatory/active_record_descendant_attribute_accessors.rb
|
76
|
+
- lib/purgatory/attribute_accessor_fields.rb
|
75
77
|
- lib/purgatory/purgatory.rb
|
76
78
|
- lib/purgatory/purgatory_module.rb
|
77
79
|
- purgatory.gemspec
|
78
80
|
- spec/purgatory_spec.rb
|
79
81
|
- spec/support/active_record.rb
|
80
82
|
- spec/support/animal.rb
|
83
|
+
- spec/support/item.rb
|
81
84
|
- spec/support/user.rb
|
82
85
|
- spec/support/widget.rb
|
83
86
|
homepage: http://github.com/financeit/purgatory
|