cia 0.3.7 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/Appraisals CHANGED
@@ -1,5 +1,6 @@
1
1
  appraise "rails2" do
2
2
  gem 'activerecord', "2.3.14"
3
+ gem 'after_commit'
3
4
  end
4
5
 
5
6
  appraise "rails3" do
@@ -1,42 +1,42 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cia (0.3.7)
4
+ cia (0.4.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
8
8
  specs:
9
- activemodel (3.2.2)
10
- activesupport (= 3.2.2)
9
+ activemodel (3.2.11)
10
+ activesupport (= 3.2.11)
11
11
  builder (~> 3.0.0)
12
- activerecord (3.2.2)
13
- activemodel (= 3.2.2)
14
- activesupport (= 3.2.2)
12
+ activerecord (3.2.11)
13
+ activemodel (= 3.2.11)
14
+ activesupport (= 3.2.11)
15
15
  arel (~> 3.0.2)
16
16
  tzinfo (~> 0.3.29)
17
- activesupport (3.2.2)
17
+ activesupport (3.2.11)
18
18
  i18n (~> 0.6)
19
19
  multi_json (~> 1.0)
20
- appraisal (0.4.1)
20
+ appraisal (0.5.1)
21
21
  bundler
22
22
  rake
23
23
  arel (3.0.2)
24
- builder (3.0.0)
25
- bump (0.3.7)
24
+ builder (3.0.4)
25
+ bump (0.3.9)
26
26
  diff-lcs (1.1.3)
27
- i18n (0.6.0)
28
- multi_json (1.3.4)
29
- rake (0.9.2)
30
- rspec (2.6.0)
31
- rspec-core (~> 2.6.0)
32
- rspec-expectations (~> 2.6.0)
33
- rspec-mocks (~> 2.6.0)
34
- rspec-core (2.6.4)
35
- rspec-expectations (2.6.0)
36
- diff-lcs (~> 1.1.2)
37
- rspec-mocks (2.6.0)
27
+ i18n (0.6.1)
28
+ multi_json (1.5.0)
29
+ rake (10.0.3)
30
+ rspec (2.12.0)
31
+ rspec-core (~> 2.12.0)
32
+ rspec-expectations (~> 2.12.0)
33
+ rspec-mocks (~> 2.12.0)
34
+ rspec-core (2.12.2)
35
+ rspec-expectations (2.12.1)
36
+ diff-lcs (~> 1.1.3)
37
+ rspec-mocks (2.12.1)
38
38
  sqlite3 (1.3.6)
39
- tzinfo (0.3.33)
39
+ tzinfo (0.3.35)
40
40
 
41
41
  PLATFORMS
42
42
  ruby
@@ -2,10 +2,12 @@
2
2
 
3
3
  source :rubygems
4
4
 
5
+ gem "bump"
5
6
  gem "rake"
6
7
  gem "rspec", "~>2"
7
8
  gem "appraisal"
8
9
  gem "sqlite3"
9
10
  gem "activerecord", "2.3.14"
11
+ gem "after_commit"
10
12
 
11
13
  gemspec :path=>"../"
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/mgrosser/code/tools/cia
3
3
  specs:
4
- cia (0.3.6)
4
+ cia (0.3.7)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
@@ -9,9 +9,12 @@ GEM
9
9
  activerecord (2.3.14)
10
10
  activesupport (= 2.3.14)
11
11
  activesupport (2.3.14)
12
+ after_commit (1.0.10)
13
+ activerecord (>= 1.15.6, < 3.0.0)
12
14
  appraisal (0.4.1)
13
15
  bundler
14
16
  rake
17
+ bump (0.3.9)
15
18
  diff-lcs (1.1.3)
16
19
  rake (0.9.2.2)
17
20
  rspec (2.10.0)
@@ -29,7 +32,9 @@ PLATFORMS
29
32
 
30
33
  DEPENDENCIES
31
34
  activerecord (= 2.3.14)
35
+ after_commit
32
36
  appraisal
37
+ bump
33
38
  cia!
34
39
  rake
35
40
  rspec (~> 2)
@@ -2,6 +2,7 @@
2
2
 
3
3
  source :rubygems
4
4
 
5
+ gem "bump"
5
6
  gem "rake"
6
7
  gem "rspec", "~>2"
7
8
  gem "appraisal"
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/mgrosser/code/tools/cia
3
3
  specs:
4
- cia (0.3.6)
4
+ cia (0.3.7)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
@@ -17,25 +17,26 @@ GEM
17
17
  activesupport (3.2.3)
18
18
  i18n (~> 0.6)
19
19
  multi_json (~> 1.0)
20
- appraisal (0.4.1)
20
+ appraisal (0.5.1)
21
21
  bundler
22
22
  rake
23
23
  arel (3.0.2)
24
- builder (3.0.0)
24
+ builder (3.0.4)
25
+ bump (0.3.9)
25
26
  diff-lcs (1.1.3)
26
- i18n (0.6.0)
27
- multi_json (1.3.5)
28
- rake (0.9.2.2)
29
- rspec (2.10.0)
30
- rspec-core (~> 2.10.0)
31
- rspec-expectations (~> 2.10.0)
32
- rspec-mocks (~> 2.10.0)
33
- rspec-core (2.10.1)
34
- rspec-expectations (2.10.0)
27
+ i18n (0.6.1)
28
+ multi_json (1.5.0)
29
+ rake (10.0.3)
30
+ rspec (2.12.0)
31
+ rspec-core (~> 2.12.0)
32
+ rspec-expectations (~> 2.12.0)
33
+ rspec-mocks (~> 2.12.0)
34
+ rspec-core (2.12.2)
35
+ rspec-expectations (2.12.1)
35
36
  diff-lcs (~> 1.1.3)
36
- rspec-mocks (2.10.1)
37
+ rspec-mocks (2.12.1)
37
38
  sqlite3 (1.3.6)
38
- tzinfo (0.3.33)
39
+ tzinfo (0.3.35)
39
40
 
40
41
  PLATFORMS
41
42
  ruby
@@ -43,6 +44,7 @@ PLATFORMS
43
44
  DEPENDENCIES
44
45
  activerecord (= 3.2.3)
45
46
  appraisal
47
+ bump
46
48
  cia!
47
49
  rake
48
50
  rspec (~> 2)
@@ -1,11 +1,8 @@
1
1
  module CIA
2
2
  module Auditable
3
3
  def self.included(base)
4
- base.class_attribute :audited_attributes, :audited_attribute_options
4
+ base.class_attribute :audited_attributes, :audited_attribute_options, :audited_attributes_callbacks_added
5
5
  base.send :extend, ClassMethods
6
- base.after_create {|record| CIA.record(:create, record) }
7
- base.after_update {|record| CIA.record(:update, record) }
8
- base.after_destroy {|record| CIA.record(:destroy, record) }
9
6
  end
10
7
 
11
8
  def cia_changes
@@ -15,17 +12,34 @@ module CIA
15
12
  module ClassMethods
16
13
  def audit_attribute(*attributes)
17
14
  options = (attributes.last.is_a?(Hash) ? attributes.pop : {})
15
+ setup_auditing_callbacks(options)
18
16
 
19
- self.audited_attributes = Set.new unless audited_attributes
20
- self.audited_attributes += attributes.map(&:to_s)
17
+ self.audited_attributes = attributes.map(&:to_s)
21
18
 
22
19
  raise "cannot have :if and :unless" if options[:if] && options[:unless]
23
- self.audited_attribute_options ||= {}
24
- self.audited_attribute_options.merge!(options)
20
+ self.audited_attribute_options = options
25
21
 
26
22
  has_many :cia_events, :class_name => "CIA::Event", :as => :source
27
23
  has_many :cia_attribute_changes, :class_name => "CIA::AttributeChange", :as => :source
28
24
  end
25
+
26
+ def setup_auditing_callbacks(options)
27
+ return if audited_attributes_callbacks_added
28
+ self.audited_attributes_callbacks_added = true
29
+
30
+ [:create, :update, :destroy].each do |callback|
31
+ method, args = if options[:callback] == :after_commit
32
+ if ActiveRecord::VERSION::MAJOR == 2
33
+ ["after_commit_on_#{callback}"]
34
+ else # rails 3+
35
+ [:after_commit, [{:on => callback}]]
36
+ end
37
+ else
38
+ ["after_#{callback}", []]
39
+ end
40
+ send(method, *args) { |record| CIA.record(callback, record) }
41
+ end
42
+ end
29
43
  end
30
44
  end
31
45
  end
@@ -1,3 +1,3 @@
1
1
  module CIA
2
- VERSION = '0.3.7'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -84,6 +84,65 @@ describe CIA do
84
84
  CIA::Event.last.action.should == "update"
85
85
  end
86
86
 
87
+ it "does not track failed changes" do
88
+ car = Car.create!(:wheels => 1).id
89
+ expect{
90
+ expect{ FailCar.new(:wheels => 4).save }.to raise_error(FailCar::Oops)
91
+ car = FailCar.find(car)
92
+ expect{ car.update_attributes(:wheels => 2) }.to raise_error(FailCar::Oops)
93
+ expect{ car.destroy }.to raise_error(FailCar::Oops)
94
+ }.to_not change{ CIA::Event.count }
95
+ end
96
+
97
+ it "is rolled back if auditing fails" do
98
+ CIA.should_receive(:record).and_raise("XXX")
99
+ expect{
100
+ expect{
101
+ CIA.audit{ object.save! }
102
+ }.to raise_error("XXX")
103
+ }.to_not change{ object.class.count }
104
+ end
105
+
106
+ context "nested classes with multiple audited_attributes" do
107
+ let(:object){ NestedCar.new }
108
+
109
+ it "has the exclusive sub-classes attributes of the nested class" do
110
+ object.class.audited_attributes.should == ["drivers"]
111
+ end
112
+
113
+ it "does not record twice for nested classes" do
114
+ expect{
115
+ CIA.audit{ object.save! }
116
+ }.to change{ CIA::Event.count }.by(+1)
117
+ end
118
+
119
+ it "does not record twice for super classes" do
120
+ expect{
121
+ CIA.audit{ Car.new.save! }
122
+ }.to change{ CIA::Event.count }.by(+1)
123
+ end
124
+ end
125
+
126
+ context "nested classes with 1 audited_attributes" do
127
+ let(:object){ InheritedCar.new }
128
+
129
+ it "has the super-classes attributes" do
130
+ object.class.audited_attributes.should == ["wheels"]
131
+ end
132
+
133
+ it "does not record twice for nested classes" do
134
+ expect{
135
+ CIA.audit{ object.save! }
136
+ }.to change{ CIA::Event.count }.by(+1)
137
+ end
138
+
139
+ it "does not record twice for super classes" do
140
+ expect{
141
+ CIA.audit{ Car.new.save! }
142
+ }.to change{ CIA::Event.count }.by(+1)
143
+ end
144
+ end
145
+
87
146
  context "custom changes" do
88
147
  let(:object) { CarWithCustomChanges.new }
89
148
 
@@ -254,6 +313,28 @@ describe CIA do
254
313
  ex.inspect.should == '#<StandardError: foo>'
255
314
  end
256
315
  end
316
+
317
+ context "with after_commit" do
318
+ let(:object){ CarWithTransactions.new }
319
+
320
+ it "still tracks" do
321
+ expect{
322
+ CIA.audit{ object.save! }
323
+ }.to change{ CIA::Event.count }.by(+1)
324
+ end
325
+
326
+ it "is not rolled back if auditing fails" do
327
+ CIA.should_receive(:record).and_raise("XXX")
328
+ begin
329
+ expect{
330
+ CIA.audit{ object.save! }
331
+ }.to change{ object.class.count }.by(+1)
332
+ rescue RuntimeError => e
333
+ # errors from after_commit are never raised in rails 3+
334
+ raise e if ActiveRecord::VERSION::MAJOR != 2 || e.message != "XXX"
335
+ end
336
+ end
337
+ end
257
338
  end
258
339
 
259
340
  context ".current_actor" do
@@ -1,5 +1,6 @@
1
1
  $LOAD_PATH.unshift 'lib'
2
2
  require 'cia'
3
+ require 'after_commit' if ActiveRecord::VERSION::MAJOR == 2
3
4
 
4
5
  RSpec.configure do |config|
5
6
  config.before do
@@ -45,8 +46,7 @@ end
45
46
  class CarWith3Attributes < ActiveRecord::Base
46
47
  self.table_name = "cars"
47
48
  include CIA::Auditable
48
- audit_attribute :wheels, :color
49
- audit_attribute :drivers
49
+ audit_attribute :wheels, :color, :drivers
50
50
  end
51
51
 
52
52
  class CarWithIf < ActiveRecord::Base
@@ -73,6 +73,32 @@ class CarWithCustomChanges < ActiveRecord::Base
73
73
  end
74
74
  end
75
75
 
76
+ class FailCar < ActiveRecord::Base
77
+ self.table_name = "cars"
78
+ include CIA::Auditable
79
+ audit_attribute :wheels
80
+
81
+ class Oops < Exception
82
+ end
83
+
84
+ after_update { |x| raise Oops }
85
+ after_create { |x| raise Oops }
86
+ after_destroy { |x| raise Oops }
87
+ end
88
+
89
+ class CarWithTransactions < ActiveRecord::Base
90
+ self.table_name = "cars"
91
+ include CIA::Auditable
92
+ audit_attribute :wheels, :callback => :after_commit
93
+ end
94
+
95
+ class NestedCar < Car
96
+ audit_attribute :drivers
97
+ end
98
+
99
+ class InheritedCar < Car
100
+ end
101
+
76
102
  def create_event(options={})
77
103
  CIA::Event.create!({:source => Car.create!, :actor => User.create!, :action => "update"}.merge(options))
78
104
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cia
3
3
  version: !ruby/object:Gem::Version
4
+ version: 0.4.0
4
5
  prerelease:
5
- version: 0.3.7
6
6
  platform: ruby
7
7
  authors:
8
8
  - Michael Grosser
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-20 00:00:00.000000000 Z
12
+ date: 2013-01-10 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description:
15
15
  email: michael@grosser.it
@@ -46,23 +46,23 @@ rdoc_options: []
46
46
  require_paths:
47
47
  - lib
48
48
  required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
49
50
  requirements:
50
51
  - - ! '>='
51
52
  - !ruby/object:Gem::Version
52
53
  version: '0'
53
54
  segments:
54
55
  - 0
55
- hash: 933978664134993553
56
- none: false
56
+ hash: 2880596585810436598
57
57
  required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
58
59
  requirements:
59
60
  - - ! '>='
60
61
  - !ruby/object:Gem::Version
61
62
  version: '0'
62
63
  segments:
63
64
  - 0
64
- hash: 933978664134993553
65
- none: false
65
+ hash: 2880596585810436598
66
66
  requirements: []
67
67
  rubyforge_project:
68
68
  rubygems_version: 1.8.24