From 1199c139cb835942a3535f0c5eb5143bf43af1b3 Mon Sep 17 00:00:00 2001 From: Lucas Souza Date: Fri, 21 Feb 2014 23:00:09 -0300 Subject: [PATCH 1/6] defining and using a custumized whodunnit --- lib/paper_trail/has_paper_trail.rb | 15 ++++++++++++--- test/unit/model_test.rb | 20 +++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/paper_trail/has_paper_trail.rb b/lib/paper_trail/has_paper_trail.rb index e1103c731..6dc9fe0a7 100644 --- a/lib/paper_trail/has_paper_trail.rb +++ b/lib/paper_trail/has_paper_trail.rb @@ -14,11 +14,11 @@ module ClassMethods # `:create`, `:update`, `:destroy` as desired. # :class_name the name of a custom Version class. This class should inherit from `PaperTrail::Version`. # :ignore an array of attributes for which a new `Version` will not be created if only they change. - # it can also aceept a Hash as an argument where the key is the attribute to ignore (a `String` or `Symbol`), + # it can also aceept a Hash as an argument where the key is the attribute to ignore (a `String` or `Symbol`), # which will only be ignored if the value is a `Proc` which returns truthily. # :if, :unless Procs that allow to specify conditions when to save versions for an object # :only inverse of `ignore` - a new `Version` will be created only for these attributes if supplied - # it can also aceept a Hash as an argument where the key is the attribute to track (a `String` or `Symbol`), + # it can also aceept a Hash as an argument where the key is the attribute to track (a `String` or `Symbol`), # which will only be counted if the value is a `Proc` which returns truthily. # :skip fields to ignore completely. As with `ignore`, updates to these fields will not create # a new `Version`. In addition, these fields will not be included in the serialized versions @@ -232,6 +232,11 @@ def touch_with_version(name = nil) save! end + def whodunnit(whodunnit) + @whodunnit = whodunnit + yield if block_given? + end + private def source_version @@ -242,7 +247,7 @@ def record_create if paper_trail_switched_on? data = { :event => paper_trail_event || 'create', - :whodunnit => PaperTrail.whodunnit + :whodunnit => _whodunnit } if changed_notably? and self.class.paper_trail_version_class.column_names.include?('object_changes') @@ -362,6 +367,10 @@ def save_version? unless_condition = self.paper_trail_options[:unless] (if_condition.blank? || if_condition.call(self)) && !unless_condition.try(:call, self) end + + def _whodunnit + @whodunnit || PaperTrail.whodunnit + end end end end diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index 27983f47e..d2bb2d3f1 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -535,6 +535,20 @@ def without(&block) @widget = Widget.new :name => 'Fidget' end + context 'defining whodunnit using a block' do + setup do + @widget.whodunnit 'Clair' do + @widget.save + end + + @version = @widget.versions.last # only 1 version + end + + should 'track who made the change' do + assert_equal 'Clair', @version.whodunnit + end + end + context 'when a record is created' do setup do PaperTrail.whodunnit = 'Alice' @@ -771,7 +785,7 @@ def without(&block) should 'store dynamic meta data based on a method of the item' do assert_equal @article.action_data_provider_method, @article.versions.last.action end - + should 'store dynamic meta data based on an attribute of the item prior to creation' do assert_equal nil, @article.versions.last.title end @@ -793,7 +807,7 @@ def without(&block) should 'store dynamic meta data which depends on the item' do assert_equal @article.id, @article.versions.last.article_id end - + should 'store dynamic meta data based on an attribute of the item prior to the update' do assert_equal @initial_title, @article.versions.last.title end @@ -814,7 +828,7 @@ def without(&block) should 'store dynamic meta data which depends on the item' do assert_equal @article.id, @article.versions.last.article_id end - + should 'store dynamic meta data based on an attribute of the item prior to the destruction' do assert_equal @initial_title, @article.versions.last.title end From 20098b247f76df0490f2c670e596d4ac35d9aa17 Mon Sep 17 00:00:00 2001 From: Lucas Souza Date: Fri, 21 Feb 2014 23:05:10 -0300 Subject: [PATCH 2/6] applying same role when a object is updated --- lib/paper_trail/has_paper_trail.rb | 2 +- test/unit/model_test.rb | 30 +++++++++++++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/lib/paper_trail/has_paper_trail.rb b/lib/paper_trail/has_paper_trail.rb index 6dc9fe0a7..83bd8fee6 100644 --- a/lib/paper_trail/has_paper_trail.rb +++ b/lib/paper_trail/has_paper_trail.rb @@ -264,7 +264,7 @@ def record_update data = { :event => paper_trail_event || 'update', :object => self.class.paper_trail_version_class.object_col_is_json? ? object_attrs : PaperTrail.serializer.dump(object_attrs), - :whodunnit => PaperTrail.whodunnit + :whodunnit => _whodunnit } if self.class.paper_trail_version_class.column_names.include?('object_changes') data[:object_changes] = self.class.paper_trail_version_class.object_changes_col_is_json? ? changes_for_paper_trail : diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index d2bb2d3f1..7c80970f5 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -536,16 +536,32 @@ def without(&block) end context 'defining whodunnit using a block' do - setup do - @widget.whodunnit 'Clair' do - @widget.save + context "when a record is created" do + setup do + @widget.whodunnit 'Clair' do + @widget.save + end + + @version = @widget.versions.last # only 1 version end - @version = @widget.versions.last # only 1 version - end + should 'track who made the change' do + assert_equal 'Clair', @version.whodunnit + end - should 'track who made the change' do - assert_equal 'Clair', @version.whodunnit + context "when a record is updated" do + setup do + @widget.whodunnit 'Rafaela' do + @widget.update_attributes :name => 'Fernandes' + end + + @version = @widget.versions.last # only 1 version + end + + should 'track who made the change' do + assert_equal 'Rafaela', @version.whodunnit + end + end end end From ca2c2935b37e1bb17a7e70ad81f0efa9f82b92a4 Mon Sep 17 00:00:00 2001 From: Lucas Souza Date: Fri, 21 Feb 2014 23:06:38 -0300 Subject: [PATCH 3/6] applying same role when a object is destroyed --- lib/paper_trail/has_paper_trail.rb | 2 +- test/unit/model_test.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/paper_trail/has_paper_trail.rb b/lib/paper_trail/has_paper_trail.rb index 83bd8fee6..a48adfed1 100644 --- a/lib/paper_trail/has_paper_trail.rb +++ b/lib/paper_trail/has_paper_trail.rb @@ -288,7 +288,7 @@ def record_destroy :item_type => self.class.base_class.name, :event => paper_trail_event || 'destroy', :object => self.class.paper_trail_version_class.object_col_is_json? ? object_attrs : PaperTrail.serializer.dump(object_attrs), - :whodunnit => PaperTrail.whodunnit + :whodunnit => _whodunnit } self.class.paper_trail_version_class.create merge_metadata(data) send(self.class.versions_association_name).send :load_target diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index 7c80970f5..8a4c62873 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -562,6 +562,20 @@ def without(&block) assert_equal 'Rafaela', @version.whodunnit end end + + context 'when a record is destroyed' do + setup do + @widget.whodunnit 'Lucas' do + @widget.destroy + end + + @version = PaperTrail::Version.last + end + + should 'track who made the change' do + assert_equal 'Lucas', @version.whodunnit + end + end end end From 34a361c896a2c44f5d0c0a20b3560ca359952336 Mon Sep 17 00:00:00 2001 From: Lucas Souza Date: Fri, 21 Feb 2014 23:15:09 -0300 Subject: [PATCH 4/6] cleaning defined whodunnit after create --- lib/paper_trail/has_paper_trail.rb | 7 +++++++ test/unit/model_test.rb | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/paper_trail/has_paper_trail.rb b/lib/paper_trail/has_paper_trail.rb index a48adfed1..deca1b7b2 100644 --- a/lib/paper_trail/has_paper_trail.rb +++ b/lib/paper_trail/has_paper_trail.rb @@ -254,6 +254,9 @@ def record_create data[:object_changes] = self.class.paper_trail_version_class.object_changes_col_is_json? ? changes_for_paper_trail : PaperTrail.serializer.dump(changes_for_paper_trail) end + + clean_whodunnit + send(self.class.versions_association_name).create! merge_metadata(data) end end @@ -295,6 +298,10 @@ def record_destroy end end + def clean_whodunnit + @whodunnit = nil + end + def merge_metadata(data) # First we merge the model-level metadata in `meta`. paper_trail_options[:meta].each do |k,v| diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index 8a4c62873..3fc7d3024 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -538,6 +538,8 @@ def without(&block) context 'defining whodunnit using a block' do context "when a record is created" do setup do + PaperTrail.whodunnit = 'Helena' + @widget.whodunnit 'Clair' do @widget.save end @@ -549,6 +551,13 @@ def without(&block) assert_equal 'Clair', @version.whodunnit end + should 'ignore defined whodunnit using global whodunnit' do + @widget.update_attributes :name => 'Fernandes' + @version = @widget.versions.last + + assert_equal 'Helena', @version.whodunnit + end + context "when a record is updated" do setup do @widget.whodunnit 'Rafaela' do From 48f2af8fabe67469b8d32b4571c6dc90ea2e74ed Mon Sep 17 00:00:00 2001 From: Lucas Souza Date: Fri, 21 Feb 2014 23:16:21 -0300 Subject: [PATCH 5/6] cleaning defined whodunnit before update --- lib/paper_trail/has_paper_trail.rb | 3 +++ test/unit/model_test.rb | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/lib/paper_trail/has_paper_trail.rb b/lib/paper_trail/has_paper_trail.rb index deca1b7b2..e73eeecad 100644 --- a/lib/paper_trail/has_paper_trail.rb +++ b/lib/paper_trail/has_paper_trail.rb @@ -273,6 +273,9 @@ def record_update data[:object_changes] = self.class.paper_trail_version_class.object_changes_col_is_json? ? changes_for_paper_trail : PaperTrail.serializer.dump(changes_for_paper_trail) end + + clean_whodunnit + send(self.class.versions_association_name).build merge_metadata(data) end end diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index 3fc7d3024..9f48a7989 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -570,6 +570,13 @@ def without(&block) should 'track who made the change' do assert_equal 'Rafaela', @version.whodunnit end + + should 'ignore defined whodunnit using global whodunnit' do + @widget.update_attributes :name => 'Souza' + @version = @widget.versions.last + + assert_equal 'Helena', @version.whodunnit + end end context 'when a record is destroyed' do From 7d185971f209328cd3acb965e5ca2d463865cf5d Mon Sep 17 00:00:00 2001 From: Lucas Souza Date: Fri, 21 Feb 2014 23:24:03 -0300 Subject: [PATCH 6/6] README --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c90dbdceb..53f68a416 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ The Rails 2.3 code is on the [`rails2`](https://github.com/airblade/paper_trail/ ### Sinatra In order to configure `PaperTrail` for usage with [Sinatra](http://www.sinatrarb.com), -your `Sinatra` app must be using `ActiveRecord` 3 or `ActiveRecord` 4. It is also recommended to use the +your `Sinatra` app must be using `ActiveRecord` 3 or `ActiveRecord` 4. It is also recommended to use the [Sinatra ActiveRecord Extension](https://github.com/janko-m/sinatra-activerecord) or something similar for managing your applications `ActiveRecord` connection in a manner similar to the way `Rails` does. If using the aforementioned `Sinatra ActiveRecord Extension`, steps for setting up your app with `PaperTrail` will look something like this: @@ -489,6 +489,21 @@ class PaperTrail::Version < ActiveRecord::Base end ``` +Sometimes you want to define who is responsible in a small scope and don't using `PaperTrail.whodunnit`. In these cases it is possible to define executing your operation inside a block: + +```ruby +PaperTrail.whodunnit = 'Andy Stewart' + +widget.whodunnit 'Lucas Souza' do + widget.update_attributes :name => 'Wibble' +end + +widget.versions.last.whodunnit # Lucas Souza + +widget.update_attributes :name => 'Clair' +widget.versions.last.whodunnit # Andy Stewart +``` + A version's `whodunnit` records who changed the object causing the `version` to be stored. Because a version stores the object as it looked before the change (see the table above), `whodunnit` returns who stopped the object looking like this -- not who made it look like this. Hence `whodunnit` is aliased as `terminator`. To find out who made a version's object look that way, use `version.originator`. And to find out who made a "live" object look like it does, use `originator` on the object.