Paper Trail Scrapbook
Human Readable audit reporting for users of PaperTrail gem.
Installation
Add PaperTrailScrapBook to your Gemfile
.
gem 'paper_trail_scrapbook'
Basic Usage
Configuration
This gem is dependent on PaperTrail,
and specifically, on the object_changes
column in the PaperTrail::Version
table. If your PaperTrail
installation does not include this column, you can
add it manually, or re-run the PaperTrail
generator:
bundle exec rake generate paper_trail:install --with_changes
If you are using an ID reference to a class (i.e. User) for whodunnit in PaperTrail, then you should configure this into PaperTrailScrapbook so it can locate and provide a human readable value for the whodunnit.
Create an initializer i.e. _config/initializers/paper_trail_scrapbook.rb
PaperTrailScrapbook.configure do |config|
config.whodunnit_class = WhoDidIt
end
You can also set the scope of your class here:
config.whodunnit_class = User.where(active: true)
And can configure a Proc to use if the user cannot be found:
config.invalid_whodunnit = proc { |id| "** missing #{id}**"}
This gem will call find
on the whodunnit class, and translate the result to a
String via to_s
. The whodunnit class can be a simple Rails model, or a custom
Ruby class that has find
class method and expects the whodunnit
value.
For example:
class WhoDidIt
def self.find(email)
Person.find_by(email: email)
end
end
PaperTrailScrapbook.config.whodunnit_class = WhoDidIt
You also have the option of seeing the most recent changes first (default is chronological)
config.recent_first = true
Life Story
The LifeStory
module provides a complete history of an object (limited by the
availability of its PaperTrail versions):
widget = Widget.find 42
text = PaperTrailScrapbook::LifeHistory.new(widget).story
# On Wednesday, 07 Jun 2017 at 2:37 PM, Rob Owens created the following Widget information:
# • email: Tim@example.com
# • name: Tim's Widget
# • built: true
# • created_by: Rob Owens[1742]
# • provider: RedCharge[3113]
# • cost: 29612.0
# • discounted_price: 29612.0
If desired, you can implement a trailed_related_content
method in your model
that returns a collection of related objects to include in the history.
The following would, for example, cause version information for the attachments
and manufacturer
to be included when viewing the life story of a Widget
:
class Widget < ApplicationRecord
has_paper_trail
def trailed_related_content
attachments | [manufacturer]
end
has_many :attachments
has_one :manufacturer
end
A history leveraging this feature might look like this:
widget = Widget.find 42
text = PaperTrailScrapbook::LifeHistory.new(widget).story
# On Monday, 05 Jun 2017 at 12:37 PM, Rob Owens created the following Manufacturer[411] information:
# • email: widgetsrus@example.com
# • name: WidgetsAreUs
# •: 411
#
# On Wednesday, 07 Jun 2017 at 2:37 PM, Rob Owens created the following Widget information:
# • email: Tim@example.com
# • name: Tim's Widget
# • manufacturer: WidgetsAreUs[411]
# •: 1234
#
# On Thursday, 23 Oct 2017 at 7:55 AM PDT, Rob Owens updated Manufacturer[411]:
# • name: WidgetsRUs
#
# On Friday, 24 Oct 2017 at 10:10 AM PDT, Rob Owens created the following Attachment[212] information:
# • name: Electromagnet
# • widget: Tim's Widget[1234]
# •: 212
#
PaperTrailScrapbook
also implements a version_filter
hook to provide a flexible way to filter which versions appear in a object's history. For example, if we only wanted our Widget
class to include history for its manufacturer after the widget was created, we might implement Widget#version_filter
like this:
class Widget < ApplicationRecord
has_paper_trail
def trailed_related_content
attachments | [manufacturer]
end
def version_filter(version)
case version.item_type
when 'Manufacturer'
if version.created_at < created_at
return nil
end
end
version
end
...
Then, the above history would be:
widget = Widget.find 42
text = PaperTrailScrapbook::LifeHistory.new(widget).story
# On Wednesday, 07 Jun 2017 at 2:37 PM, Rob Owens created the following Widget information:
# • email: Tim@example.com
# • name: Tim's Widget
# • manufacturer: WidgetsAreUs[411]
# •: 1234
#
# On Thursday, 23 Oct 2017 at 7:55 AM PDT, Rob Owens updated Manufacturer[411]:
# • name: WidgetsRUs
#
# On Friday, 24 Oct 2017 at 10:10 AM PDT, Rob Owens created the following Attachment[212] information:
# • name: Electromagnet
# • widget: Tim's Widget[1234]
# •: 212
#
User Journal
The UserJournal
module provides a list of changes made by a particular
whodunnit:
who = WhoDidIt.find 42
text = PaperTrailScrapbook::UserJournal.new(who).story
# Between Wednesday, 31 Dec 1969 at 4:00 PM PST and Friday, 26 Jan 2018 at 10:35 AM PST, Rob Owens made the following changes:
#
# On Wednesday, 07 Jan 2018 at 2:37 PM, created the following Widget information:
# • email: Tim@example.com
# • name: Tim's Widget
# • built: true
# • created_by: Rob Owens[1742]
# • provider: RedCharge[3113]
# • cost: 29612.0
# • discounted_price: 29612.0
# •: 123
#
# On Thursday, 23 Oct 2017 at 7:55 AM PDT, updated Timer[595]:
# • reset_at: 2017-10-23 15:55:22 UTC was *removed*
# • job reference: 354524 was *removed*
#
# On Friday, 22 Oct 2017 at 12:43 PM PDT, updated Prospect[5124]:
# • business: 1189 added
#
# On Friday, 07 Oct 2017 at 12:43 PM PDT, created Prospect[5952]:
# • name: Car Scrub
# • first_contact: 2017-10-07
# • created by: Rob Owens[42]
You can also scope the change list to a specific class:
text = PaperTrailScrapbook::UserJournal.new(who, klass: Widget).story
# Between Wednesday, 31 Dec 1969 at 4:00 PM PST and Friday, 26 Jan 2018 at 10:35 AM PST, Rob Owens made the following Widget changes:
#
# On Wednesday, 07 Jan 2018 at 2:37 PM, created Widget[123]:
# • email: Tim@example.com
# • name: Tim's Widget
# • built: true
# • created_by: Rob Owens[1742]
# • provider: RedCharge[3113]
# • cost: 29612.0
# • discounted_price: 29612.0
# •: 123
Or view changes in a time range:
text = PaperTrailScrapbook::UserJournal.new(who, start: 1.month.ago, end: Time.now).story
# Between Tuesday, 26 Dec 2017 at 4:00 PM PST and Friday, 26 Jan 2018 at 4:00 PM PST, Rob Owens made the following changes:
#
# On Wednesday, 07 Jan 2018 at 2:37 PM, created the following Widget information:
# • email: Tim@example.com
# • name: Tim's Widget
# • built: true
# • created_by: Rob Owens[1742]
# • provider: RedCharge[3113]
# • cost: 29612.0
# • discounted_price: 29612.0
# •: 123
Problems
Please use GitHub's issue tracker.
Contributors
- Created by Tim Chambers in 2017
- Jason Dinsmore
- All other contributors
Acknowledgement and kudos to Andy Stewart, Ben Atkins, Jared Beck, and all the other contributors to the PaperTrail gem. Without them this would not be possible.
Intellectual Property
Copyright (c) 2017 Hint Media, Inc. Released under the MIT licence.