Module: Auditable::Auditing
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/auditable/auditing.rb
Defined Under Namespace
Modules: ClassMethods
Instance Attribute Summary collapse
-
#audit_action ⇒ Object
INSTANCE METHODS.
-
#audit_tag ⇒ Object
INSTANCE METHODS.
Instance Method Summary collapse
- #audit_changed_by ⇒ Object
-
#audit_tag_with(tag) ⇒ Object
Mark the latest record with a tag in order to easily find and perform diff against later If there are no audits for this record, create a new audit with this tag.
-
#audited_changes(options = {}) ⇒ Object
Get the latest changes by comparing the latest two audits.
-
#last_audit ⇒ Object
Get the latest audit record.
-
#last_change_of(attribute) ⇒ Object
Return last attribute’s change.
- #save_audit(data) ⇒ Object
-
#snap ⇒ Object
Take a snapshot of the current state of the audited record’s audited attributes.
-
#snap!(options = {}) ⇒ Object
Take a snapshot of and save the current state of the audited record’s audited attributes.
Instance Attribute Details
#audit_action ⇒ Object
INSTANCE METHODS
170 171 172 |
# File 'lib/auditable/auditing.rb', line 170 def audit_action @audit_action end |
#audit_tag ⇒ Object
INSTANCE METHODS
170 171 172 |
# File 'lib/auditable/auditing.rb', line 170 def audit_tag @audit_tag end |
Instance Method Details
#audit_changed_by ⇒ Object
172 173 174 175 176 177 178 179 180 |
# File 'lib/auditable/auditing.rb', line 172 def audit_changed_by changed_by_call = self.class.audited_cache('changed_by') if changed_by_call.respond_to? :call changed_by_call.call(self) else self.send(changed_by_call) end end |
#audit_tag_with(tag) ⇒ Object
Mark the latest record with a tag in order to easily find and perform diff against later If there are no audits for this record, create a new audit with this tag
196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/auditable/auditing.rb', line 196 def audit_tag_with(tag) if audit = last_audit audit.update_attribute(:tag, tag) # Force the trigger of a reload if audited_version is used. Happens automatically otherwise audits.reload if self.class.audited_version else self.audit_tag = tag snap! end end |
#audited_changes(options = {}) ⇒ Object
Get the latest changes by comparing the latest two audits
282 283 284 |
# File 'lib/auditable/auditing.rb', line 282 def audited_changes( = {}) last_audit.try(:latest_diff, ) || {} end |
#last_audit ⇒ Object
Get the latest audit record
183 184 185 186 187 188 189 190 191 192 |
# File 'lib/auditable/auditing.rb', line 183 def last_audit # if version is enabled, use the version if self.class.audited_version audits.order('version DESC').first # other pull last inserted else audits.last end end |
#last_change_of(attribute) ⇒ Object
Return last attribute’s change
This method may be slow and inefficient on model with lots of audit objects. Go through each audit in the reverse order and find the first occurrence when audit.modifications changed
291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/auditable/auditing.rb', line 291 def last_change_of(attribute) raise "#{attribute} is not audited for model #{self.class}. Audited attributes: #{self.class.audited_attributes}" unless self.class.audited_attributes.include? attribute.to_sym attribute = attribute.to_s # support symbol as well last = audits.size - 1 last.downto(1) do |i| if audits[i].modifications[attribute] != audits[i-1].modifications[attribute] return audits[i].diff(audits[i-1])[attribute] end end nil end |
#save_audit(data) ⇒ Object
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/auditable/auditing.rb', line 251 def save_audit(data) last_saved_audit = last_audit # build new audit audit = audits.build(data) # only save if it's different from before if !audit.same_audited_content?(last_saved_audit) # If version is enabled, wrap in a transaction to get the next version number # before saving if self.class.audited_version ActiveRecord::Base.transaction do if self.class.audited_version.is_a? Symbol audit.version = self.send( self.class.audited_version ) else audit.version = (audits.maximum('version')||0) + 1 end audit.save end # Save as usual else audit.save end else audits.delete(audit) end end |
#snap ⇒ Object
Take a snapshot of the current state of the audited record’s audited attributes
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/auditable/auditing.rb', line 209 def snap serialize_attribute = lambda do |attribute| # If a proc, do nothing, cannot be serialized # XXX: raise warning on passing in a proc? if attribute.is_a? Proc # noop # Is an ActiveRecord, serialize as hash instead of serializing the object elsif attribute.class.ancestors.include?(ActiveRecord::Base) attribute.serializable_hash # If an array, such as from an association, serialize the elements in the array elsif attribute.is_a?(Array) || attribute.is_a?(ActiveRecord::Associations::CollectionProxy) attribute.map { |element| serialize_attribute.call(element) } # otherwise, return val else attribute end end {}.tap do |s| self.class.audited_attributes.each do |attr| val = self.send attr s[attr.to_s] = serialize_attribute.call(val) end end end |
#snap!(options = {}) ⇒ Object
Take a snapshot of and save the current state of the audited record’s audited attributes
Accept values for :tag, :action and :user in the argument hash. However, these are overridden by the values set by the auditable record’s virtual attributes (#audit_tag, #audit_action, #changed_by) if defined
241 242 243 244 245 246 247 248 249 |
# File 'lib/auditable/auditing.rb', line 241 def snap!( = {}) data = .merge(:modifications => self.snap) data[:tag] = self.audit_tag if self.audit_tag data[:action] = self.audit_action if self.audit_action data[:changed_by] = self.audit_changed_by if self.audit_changed_by self.save_audit( data ) end |