acts_as_audited_collection 0.3 → 0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|