acts_as_audited_collection 0.3 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +34 -37
- data/init.rb +1 -3
- data/lib/active_record/acts/audited_collection.rb +222 -0
- data/lib/acts_as_audited_collection.rb +3 -229
- data/lib/acts_as_audited_collection/railtie.rb +10 -0
- data/spec/debug.log +364 -56748
- metadata +28 -26
- data/rails/init.rb +0 -5
- data/spec/db/acts_as_audited_collection.sqlite3.db +0 -0
data/Rakefile
CHANGED
@@ -1,45 +1,42 @@
|
|
1
1
|
require 'rake'
|
2
|
-
require '
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rdoc/task'
|
3
4
|
|
4
|
-
|
5
|
-
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
'
|
10
|
-
'
|
11
|
-
'
|
12
|
-
|
13
|
-
]
|
14
|
-
|
15
|
-
spec = Gem::Specification.new do |s|
|
16
|
-
s.name = 'acts_as_audited_collection'
|
17
|
-
s.version = '0.3'
|
18
|
-
s.author = 'Shaun Mangelsdorf'
|
19
|
-
s.email = 's.mangelsdorf@gmail.com'
|
20
|
-
s.homepage = 'http://smangelsdorf.github.com'
|
21
|
-
s.platform = Gem::Platform::RUBY
|
22
|
-
s.summary = 'Extends ActiveRecord to allow auditing of associations'
|
23
|
-
s.files = PKG_FILES.to_a
|
24
|
-
s.require_path = 'lib'
|
25
|
-
s.has_rdoc = false
|
26
|
-
s.extra_rdoc_files = ['README.md']
|
27
|
-
s.rubyforge_project = 'auditcollection'
|
28
|
-
s.description = <<EOF
|
29
|
-
Adds auditing capabilities to ActiveRecord associations, in a similar fashion to acts_as_audited.
|
30
|
-
EOF
|
8
|
+
desc 'Test the acts_as_audited_collection plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.libs << 'test'
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
31
14
|
end
|
32
15
|
|
33
|
-
desc '
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
16
|
+
desc 'Generate documentation for the acts_as_audited_collection plugin.'
|
17
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = 'ActsAsAuditedCollection'
|
20
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
21
|
+
rdoc.rdoc_files.include('README')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
40
23
|
end
|
41
24
|
|
42
|
-
|
43
|
-
|
44
|
-
|
25
|
+
begin
|
26
|
+
require 'jeweler'
|
27
|
+
Jeweler::Tasks.new do |gem|
|
28
|
+
gem.name = 'acts_as_audited_collection'
|
29
|
+
gem.summary = 'Adds auditing capabilities to ActiveRecord associations, in a similar fashion to acts_as_audited.'
|
30
|
+
gem.files = Dir[
|
31
|
+
'[a-zA-Z]*',
|
32
|
+
'generators/**/*',
|
33
|
+
'lib/**/*',
|
34
|
+
'rails/**/*',
|
35
|
+
'spec/**/*'
|
36
|
+
]
|
37
|
+
gem.authors = ['Shaun Mangelsdorf']
|
38
|
+
gem.version = '0.4'
|
39
|
+
end
|
40
|
+
rescue LoadError
|
41
|
+
puts "Jeweler could not be sourced"
|
45
42
|
end
|
data/init.rb
CHANGED
@@ -0,0 +1,222 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Acts
|
3
|
+
module AuditedCollection
|
4
|
+
module ClassMethods
|
5
|
+
def acts_as_audited_collection(options = {})
|
6
|
+
unless self.included_modules.include?(InstanceMethods)
|
7
|
+
# First time use in this class, we have some extra work to do.
|
8
|
+
send :include, InstanceMethods
|
9
|
+
|
10
|
+
class_inheritable_reader :audited_collections
|
11
|
+
write_inheritable_attribute :audited_collections, {}
|
12
|
+
attr_accessor :collection_audit_object_is_soft_deleted
|
13
|
+
|
14
|
+
after_create :collection_audit_create
|
15
|
+
before_update :collection_audit_update
|
16
|
+
after_destroy :collection_audit_destroy
|
17
|
+
|
18
|
+
has_many :child_collection_audits, :as => :child_record,
|
19
|
+
:class_name => 'CollectionAudit'
|
20
|
+
end
|
21
|
+
|
22
|
+
options = {
|
23
|
+
:name => self.name.tableize.to_sym,
|
24
|
+
:cascade => false,
|
25
|
+
:track_modifications => false,
|
26
|
+
:only => nil,
|
27
|
+
:except => nil,
|
28
|
+
:soft_delete => nil
|
29
|
+
}.merge(options)
|
30
|
+
|
31
|
+
options[:only] &&= [options[:only]].flatten.collect(&:to_s)
|
32
|
+
options[:except] &&= [options[:except]].flatten.collect(&:to_s)
|
33
|
+
|
34
|
+
unless options.has_key? :parent
|
35
|
+
raise ActiveRecord::ConfigurationError.new "Must specify parent for an acts_as_audited_collection (:parent => :object)"
|
36
|
+
end
|
37
|
+
|
38
|
+
parent_association = reflect_on_association(options[:parent])
|
39
|
+
unless parent_association && parent_association.belongs_to?
|
40
|
+
raise ActiveRecord::ConfigurationError.new "Parent association '#{options[:parent]}' must be a belongs_to relationship"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Try explicit first, then default
|
44
|
+
options[:foreign_key] ||= parent_association.options[:foreign_key]
|
45
|
+
options[:foreign_key] ||= parent_association.primary_key_name
|
46
|
+
|
47
|
+
# TODO Remove this when polymorphic is supported.
|
48
|
+
if parent_association.options[:polymorphic]
|
49
|
+
raise ActiveRecord::ConfigurationError.new "Sorry, acts_as_audited_collection polymorphic associations haven't been added yet."
|
50
|
+
end
|
51
|
+
|
52
|
+
options[:parent_type] ||= parent_association.klass.name
|
53
|
+
|
54
|
+
define_acts_as_audited_collection options do |config|
|
55
|
+
config.merge! options
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def acts_as_audited_collection_parent(options = {})
|
60
|
+
unless options.has_key? :for
|
61
|
+
raise ActiveRecord::ConfigurationError.new "Must specify relationship for an acts_as_audited_collection_parent (:for => :objects)"
|
62
|
+
end
|
63
|
+
|
64
|
+
child_association = reflect_on_association(options[:for])
|
65
|
+
if child_association.nil? || child_association.belongs_to?
|
66
|
+
raise ActiveRecord::ConfigurationError.new "Association '#{options[:for]}' must be a valid parent (i.e. not belongs_to) relationship"
|
67
|
+
end
|
68
|
+
|
69
|
+
has_many :"#{options[:for]}_audits", :as => :parent_record,
|
70
|
+
:class_name => 'CollectionAudit',
|
71
|
+
:conditions => ['association = ?', options[:for].to_s]
|
72
|
+
end
|
73
|
+
|
74
|
+
def define_acts_as_audited_collection(options)
|
75
|
+
yield(read_inheritable_attribute(:audited_collections)[options[:name]] ||= {})
|
76
|
+
end
|
77
|
+
|
78
|
+
def without_collection_audit
|
79
|
+
result = nil
|
80
|
+
Thread.current[:collection_audit_enabled] = returning(Thread.current[:collection_audit_enabled]) do
|
81
|
+
Thread.current[:collection_audit_enabled] = false
|
82
|
+
result = yield if block_given?
|
83
|
+
end
|
84
|
+
|
85
|
+
result
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
module InstanceMethods
|
90
|
+
protected
|
91
|
+
def collection_audit_create
|
92
|
+
collection_audit_write :action => 'add', :attributes => audited_collection_attributes
|
93
|
+
end
|
94
|
+
|
95
|
+
def collection_audit_update
|
96
|
+
audited_collections.each do |name, opts|
|
97
|
+
attributes = {opts[:foreign_key] => self.send(opts[:foreign_key])}
|
98
|
+
if collection_audit_is_soft_deleted?(opts)
|
99
|
+
collection_audit_write(
|
100
|
+
:action => 'remove',
|
101
|
+
:attributes => attributes
|
102
|
+
) unless collection_audit_was_soft_deleted?(opts)
|
103
|
+
elsif collection_audit_was_soft_deleted?(opts)
|
104
|
+
collection_audit_write :action => 'add', :attributes => attributes
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
unless (old_values = audited_collection_attribute_changes).empty?
|
109
|
+
new_values = old_values.inject({}) { |map, (k, v)| map[k] = self[k]; map }
|
110
|
+
|
111
|
+
collection_audit_write :action => 'remove', :attributes => old_values
|
112
|
+
collection_audit_write :action => 'add', :attributes => new_values
|
113
|
+
end
|
114
|
+
|
115
|
+
collection_audit_write_as_modified unless audited_collection_excluded_attribute_changes.empty?
|
116
|
+
end
|
117
|
+
|
118
|
+
def collection_audit_destroy
|
119
|
+
collection_audit_write :action => 'remove', :attributes => audited_collection_attributes
|
120
|
+
end
|
121
|
+
|
122
|
+
def collection_audit_write_as_modified(child_audit=nil)
|
123
|
+
each_modification_tracking_audited_collection do |col|
|
124
|
+
collection_audit_write(:action => 'modify',
|
125
|
+
:attributes => attributes.slice(col[:foreign_key]),
|
126
|
+
:child_audit => child_audit
|
127
|
+
) if audited_collection_should_care?(col)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def collection_audit_cascade(child, child_audit)
|
132
|
+
collection_audit_write_as_modified(child_audit) if respond_to? :audited_collections
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
def collection_audit_is_soft_deleted?(opts)
|
137
|
+
if opts[:soft_delete]
|
138
|
+
opts[:soft_delete].all?{|k,v| self.send(k) == v}
|
139
|
+
else
|
140
|
+
false
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def collection_audit_was_soft_deleted?(opts)
|
145
|
+
if opts[:soft_delete]
|
146
|
+
opts[:soft_delete].all?{|k,v| self.send(:"#{k}_was") == v}
|
147
|
+
else
|
148
|
+
false
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def collection_audit_write(opts)
|
153
|
+
# Only care about explicit false here, not the falseness of nil
|
154
|
+
return if Thread.current[:collection_audit_enabled] == false
|
155
|
+
|
156
|
+
mappings = audited_relation_attribute_mappings
|
157
|
+
opts[:attributes].reject{|k,v| v.nil?}.each do |fk, fk_val|
|
158
|
+
object_being_deleted = collection_audit_is_soft_deleted?(mappings[fk]) &&
|
159
|
+
!collection_audit_was_soft_deleted?(mappings[fk])
|
160
|
+
object_being_restored = collection_audit_was_soft_deleted?(mappings[fk]) &&
|
161
|
+
!collection_audit_is_soft_deleted?(mappings[fk])
|
162
|
+
object_is_deleted = collection_audit_is_soft_deleted?(mappings[fk]) &&
|
163
|
+
collection_audit_was_soft_deleted?(mappings[fk])
|
164
|
+
|
165
|
+
unless (object_being_deleted and opts[:action] != 'remove') or
|
166
|
+
(object_being_restored and opts[:action] != 'add') or
|
167
|
+
object_is_deleted
|
168
|
+
|
169
|
+
audit = child_collection_audits.create :parent_record_id => fk_val,
|
170
|
+
:parent_record_type => mappings[fk][:parent_type],
|
171
|
+
:action => opts[:action],
|
172
|
+
:association => mappings[fk][:name].to_s,
|
173
|
+
:child_audit => opts[:child_audit]
|
174
|
+
|
175
|
+
if mappings[fk][:cascade]
|
176
|
+
parent = mappings[fk][:parent_type].constantize.send :find, fk_val
|
177
|
+
parent.collection_audit_cascade(self, audit)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def each_modification_tracking_audited_collection
|
184
|
+
audited_collections.each do |name, options|
|
185
|
+
if options[:track_modifications]
|
186
|
+
yield options
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def audited_collection_attributes
|
192
|
+
attributes.slice *audited_relation_attribute_mappings.keys
|
193
|
+
end
|
194
|
+
|
195
|
+
def audited_collection_excluded_attribute_changes
|
196
|
+
changed_attributes.except *audited_relation_attribute_mappings.keys
|
197
|
+
end
|
198
|
+
|
199
|
+
def audited_collection_attribute_changes
|
200
|
+
changed_attributes.slice *audited_relation_attribute_mappings.keys
|
201
|
+
end
|
202
|
+
|
203
|
+
def audited_collection_should_care?(collection)
|
204
|
+
if collection[:only]
|
205
|
+
!audited_collection_excluded_attribute_changes.slice(*collection[:only]).empty?
|
206
|
+
elsif collection[:except]
|
207
|
+
!audited_collection_excluded_attribute_changes.except(*collection[:except]).empty?
|
208
|
+
else
|
209
|
+
true
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def audited_relation_attribute_mappings
|
214
|
+
audited_collections.inject({}) do |map, (name, options)|
|
215
|
+
map[options[:foreign_key]] = options
|
216
|
+
map
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -1,230 +1,4 @@
|
|
1
|
-
|
1
|
+
require 'acts_as_audited_collection/collection_audit'
|
2
|
+
require 'active_record/acts/audited_collection'
|
2
3
|
|
3
|
-
require 'acts_as_audited_collection/
|
4
|
-
|
5
|
-
module ActiveRecord
|
6
|
-
module Acts
|
7
|
-
module AuditedCollection
|
8
|
-
def self.included(base)
|
9
|
-
base.extend ClassMethods
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
def acts_as_audited_collection(options = {})
|
14
|
-
unless self.included_modules.include?(InstanceMethods)
|
15
|
-
# First time use in this class, we have some extra work to do.
|
16
|
-
send :include, InstanceMethods
|
17
|
-
|
18
|
-
class_inheritable_reader :audited_collections
|
19
|
-
write_inheritable_attribute :audited_collections, {}
|
20
|
-
attr_accessor :collection_audit_object_is_soft_deleted
|
21
|
-
|
22
|
-
after_create :collection_audit_create
|
23
|
-
before_update :collection_audit_update
|
24
|
-
after_destroy :collection_audit_destroy
|
25
|
-
|
26
|
-
has_many :child_collection_audits, :as => :child_record,
|
27
|
-
:class_name => 'CollectionAudit'
|
28
|
-
end
|
29
|
-
|
30
|
-
options = {
|
31
|
-
:name => self.name.tableize.to_sym,
|
32
|
-
:cascade => false,
|
33
|
-
:track_modifications => false,
|
34
|
-
:only => nil,
|
35
|
-
:except => nil,
|
36
|
-
:soft_delete => nil
|
37
|
-
}.merge(options)
|
38
|
-
|
39
|
-
options[:only] &&= [options[:only]].flatten.collect(&:to_s)
|
40
|
-
options[:except] &&= [options[:except]].flatten.collect(&:to_s)
|
41
|
-
|
42
|
-
unless options.has_key? :parent
|
43
|
-
raise ActiveRecord::ConfigurationError.new "Must specify parent for an acts_as_audited_collection (:parent => :object)"
|
44
|
-
end
|
45
|
-
|
46
|
-
parent_association = reflect_on_association(options[:parent])
|
47
|
-
unless parent_association && parent_association.belongs_to?
|
48
|
-
raise ActiveRecord::ConfigurationError.new "Parent association '#{options[:parent]}' must be a belongs_to relationship"
|
49
|
-
end
|
50
|
-
|
51
|
-
# Try explicit first, then default
|
52
|
-
options[:foreign_key] ||= parent_association.options[:foreign_key]
|
53
|
-
options[:foreign_key] ||= parent_association.primary_key_name
|
54
|
-
|
55
|
-
# TODO Remove this when polymorphic is supported.
|
56
|
-
if parent_association.options[:polymorphic]
|
57
|
-
raise ActiveRecord::ConfigurationError.new "Sorry, acts_as_audited_collection polymorphic associations haven't been added yet."
|
58
|
-
end
|
59
|
-
|
60
|
-
options[:parent_type] ||= parent_association.klass.name
|
61
|
-
|
62
|
-
define_acts_as_audited_collection options do |config|
|
63
|
-
config.merge! options
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def acts_as_audited_collection_parent(options = {})
|
68
|
-
unless options.has_key? :for
|
69
|
-
raise ActiveRecord::ConfigurationError.new "Must specify relationship for an acts_as_audited_collection_parent (:for => :objects)"
|
70
|
-
end
|
71
|
-
|
72
|
-
child_association = reflect_on_association(options[:for])
|
73
|
-
if child_association.nil? || child_association.belongs_to?
|
74
|
-
raise ActiveRecord::ConfigurationError.new "Association '#{options[:for]}' must be a valid parent (i.e. not belongs_to) relationship"
|
75
|
-
end
|
76
|
-
|
77
|
-
has_many :"#{options[:for]}_audits", :as => :parent_record,
|
78
|
-
:class_name => 'CollectionAudit',
|
79
|
-
:conditions => ['association = ?', options[:for].to_s]
|
80
|
-
end
|
81
|
-
|
82
|
-
def define_acts_as_audited_collection(options)
|
83
|
-
yield(read_inheritable_attribute(:audited_collections)[options[:name]] ||= {})
|
84
|
-
end
|
85
|
-
|
86
|
-
def without_collection_audit
|
87
|
-
result = nil
|
88
|
-
Thread.current[:collection_audit_enabled] = returning(Thread.current[:collection_audit_enabled]) do
|
89
|
-
Thread.current[:collection_audit_enabled] = false
|
90
|
-
result = yield if block_given?
|
91
|
-
end
|
92
|
-
|
93
|
-
result
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
module InstanceMethods
|
98
|
-
protected
|
99
|
-
def collection_audit_create
|
100
|
-
collection_audit_write :action => 'add', :attributes => audited_collection_attributes
|
101
|
-
end
|
102
|
-
|
103
|
-
def collection_audit_update
|
104
|
-
audited_collections.each do |name, opts|
|
105
|
-
attributes = {opts[:foreign_key] => self.send(opts[:foreign_key])}
|
106
|
-
if collection_audit_is_soft_deleted?(opts)
|
107
|
-
collection_audit_write(
|
108
|
-
:action => 'remove',
|
109
|
-
:attributes => attributes
|
110
|
-
) unless collection_audit_was_soft_deleted?(opts)
|
111
|
-
elsif collection_audit_was_soft_deleted?(opts)
|
112
|
-
collection_audit_write :action => 'add', :attributes => attributes
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
unless (old_values = audited_collection_attribute_changes).empty?
|
117
|
-
new_values = old_values.inject({}) { |map, (k, v)| map[k] = self[k]; map }
|
118
|
-
|
119
|
-
collection_audit_write :action => 'remove', :attributes => old_values
|
120
|
-
collection_audit_write :action => 'add', :attributes => new_values
|
121
|
-
end
|
122
|
-
|
123
|
-
collection_audit_write_as_modified unless audited_collection_excluded_attribute_changes.empty?
|
124
|
-
end
|
125
|
-
|
126
|
-
def collection_audit_destroy
|
127
|
-
collection_audit_write :action => 'remove', :attributes => audited_collection_attributes
|
128
|
-
end
|
129
|
-
|
130
|
-
def collection_audit_write_as_modified(child_audit=nil)
|
131
|
-
each_modification_tracking_audited_collection do |col|
|
132
|
-
collection_audit_write(:action => 'modify',
|
133
|
-
:attributes => attributes.slice(col[:foreign_key]),
|
134
|
-
:child_audit => child_audit
|
135
|
-
) if audited_collection_should_care?(col)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def collection_audit_cascade(child, child_audit)
|
140
|
-
collection_audit_write_as_modified(child_audit) if respond_to? :audited_collections
|
141
|
-
end
|
142
|
-
|
143
|
-
private
|
144
|
-
def collection_audit_is_soft_deleted?(opts)
|
145
|
-
if opts[:soft_delete]
|
146
|
-
opts[:soft_delete].all?{|k,v| self.send(k) == v}
|
147
|
-
else
|
148
|
-
false
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def collection_audit_was_soft_deleted?(opts)
|
153
|
-
if opts[:soft_delete]
|
154
|
-
opts[:soft_delete].all?{|k,v| self.send(:"#{k}_was") == v}
|
155
|
-
else
|
156
|
-
false
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
def collection_audit_write(opts)
|
161
|
-
# Only care about explicit false here, not the falseness of nil
|
162
|
-
return if Thread.current[:collection_audit_enabled] == false
|
163
|
-
|
164
|
-
mappings = audited_relation_attribute_mappings
|
165
|
-
opts[:attributes].reject{|k,v| v.nil?}.each do |fk, fk_val|
|
166
|
-
object_being_deleted = collection_audit_is_soft_deleted?(mappings[fk]) &&
|
167
|
-
!collection_audit_was_soft_deleted?(mappings[fk])
|
168
|
-
object_being_restored = collection_audit_was_soft_deleted?(mappings[fk]) &&
|
169
|
-
!collection_audit_is_soft_deleted?(mappings[fk])
|
170
|
-
object_is_deleted = collection_audit_is_soft_deleted?(mappings[fk]) &&
|
171
|
-
collection_audit_was_soft_deleted?(mappings[fk])
|
172
|
-
|
173
|
-
unless (object_being_deleted and opts[:action] != 'remove') or
|
174
|
-
(object_being_restored and opts[:action] != 'add') or
|
175
|
-
object_is_deleted
|
176
|
-
|
177
|
-
audit = child_collection_audits.create :parent_record_id => fk_val,
|
178
|
-
:parent_record_type => mappings[fk][:parent_type],
|
179
|
-
:action => opts[:action],
|
180
|
-
:association => mappings[fk][:name].to_s,
|
181
|
-
:child_audit => opts[:child_audit]
|
182
|
-
|
183
|
-
if mappings[fk][:cascade]
|
184
|
-
parent = mappings[fk][:parent_type].constantize.send :find, fk_val
|
185
|
-
parent.collection_audit_cascade(self, audit)
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def each_modification_tracking_audited_collection
|
192
|
-
audited_collections.each do |name, options|
|
193
|
-
if options[:track_modifications]
|
194
|
-
yield options
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
def audited_collection_attributes
|
200
|
-
attributes.slice *audited_relation_attribute_mappings.keys
|
201
|
-
end
|
202
|
-
|
203
|
-
def audited_collection_excluded_attribute_changes
|
204
|
-
changed_attributes.except *audited_relation_attribute_mappings.keys
|
205
|
-
end
|
206
|
-
|
207
|
-
def audited_collection_attribute_changes
|
208
|
-
changed_attributes.slice *audited_relation_attribute_mappings.keys
|
209
|
-
end
|
210
|
-
|
211
|
-
def audited_collection_should_care?(collection)
|
212
|
-
if collection[:only]
|
213
|
-
!audited_collection_excluded_attribute_changes.slice(*collection[:only]).empty?
|
214
|
-
elsif collection[:except]
|
215
|
-
!audited_collection_excluded_attribute_changes.except(*collection[:except]).empty?
|
216
|
-
else
|
217
|
-
true
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
def audited_relation_attribute_mappings
|
222
|
-
audited_collections.inject({}) do |map, (name, options)|
|
223
|
-
map[options[:foreign_key]] = options
|
224
|
-
map
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
4
|
+
require 'acts_as_audited_collection/railtie' if defined? Rails
|