close #334; Add small-scope 'whodunnit' method to PaperTrail::Model::InstanceMethods
This commit is contained in:
parent
52823d2fb2
commit
44a632eea6
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
- [#340](https://github.com/airblade/paper_trail/issues/340) - Prevent potential error encountered when using the `InstallGenerator`
|
- [#340](https://github.com/airblade/paper_trail/issues/340) - Prevent potential error encountered when using the `InstallGenerator`
|
||||||
with Rails `4.1.0.rc1`.
|
with Rails `4.1.0.rc1`.
|
||||||
|
- [#334](https://github.com/airblade/paper_trail/pull/334) - Add small-scope `whodunnit` method to `PaperTrail::Model::InstanceMethods`.
|
||||||
- [#329](https://github.com/airblade/paper_trail/issues/329) - Add `touch_with_version` method to `PaperTrail::Model::InstanceMethods`,
|
- [#329](https://github.com/airblade/paper_trail/issues/329) - Add `touch_with_version` method to `PaperTrail::Model::InstanceMethods`,
|
||||||
to allow for generating a version `touch`ing a model.
|
to allow for generating a version `touch`ing a model.
|
||||||
- [#328](https://github.com/airblade/paper_trail/pull/328) / [#326](https://github.com/airblade/paper_trail/issues/326)/
|
- [#328](https://github.com/airblade/paper_trail/pull/328) / [#326](https://github.com/airblade/paper_trail/issues/326) /
|
||||||
[#307](https://github.com/airblade/paper_trail/issues/307) - `Model.paper_trail_enabled_for_model?` and
|
[#307](https://github.com/airblade/paper_trail/issues/307) - `Model.paper_trail_enabled_for_model?` and
|
||||||
`model_instance.without_versioning` is now thread-safe.
|
`model_instance.without_versioning` is now thread-safe.
|
||||||
- [#316](https://github.com/airblade/paper_trail/issues/316) - `user_for_paper_trail` should default to `current_user.try(:id)`
|
- [#316](https://github.com/airblade/paper_trail/issues/316) - `user_for_paper_trail` should default to `current_user.try(:id)`
|
||||||
|
|
30
README.md
30
README.md
|
@ -57,7 +57,7 @@ The Rails 2.3 code is on the [`rails2`](https://github.com/airblade/paper_trail/
|
||||||
### Sinatra
|
### Sinatra
|
||||||
|
|
||||||
In order to configure `PaperTrail` for usage with [Sinatra](http://www.sinatrarb.com),
|
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
|
[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
|
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:
|
`Sinatra ActiveRecord Extension`, steps for setting up your app with `PaperTrail` will look something like this:
|
||||||
|
@ -480,15 +480,32 @@ In a console session you can manually set who is responsible like this:
|
||||||
You can avoid having to do this manually by setting your initializer to pick up the username of the current user from the OS, like this:
|
You can avoid having to do this manually by setting your initializer to pick up the username of the current user from the OS, like this:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
class PaperTrail::Version < ActiveRecord::Base
|
# config/initializers/paper_trail.rb
|
||||||
if defined?(Rails::Console)
|
module PaperTrail
|
||||||
PaperTrail.whodunnit = "#{`whoami`.strip}: console"
|
class Version < ActiveRecord::Base
|
||||||
elsif File.basename($0) == "rake"
|
if defined?(Rails::Console)
|
||||||
PaperTrail.whodunnit = "#{`whoami`.strip}: rake #{ARGV.join ' '}"
|
PaperTrail.whodunnit = "#{`whoami`.strip}: console"
|
||||||
|
elsif File.basename($0) == "rake"
|
||||||
|
PaperTrail.whodunnit = "#{`whoami`.strip}: rake #{ARGV.join ' '}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Sometimes you want to define who is responsible for a change in a small scope without overwriting value of `PaperTrail.whodunnit`. It is possible to define the `whodunnit` value for an operation inside a block like this:
|
||||||
|
|
||||||
|
```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
|
||||||
|
>> widget.whodunnit('Ben Atkins') { |w| w.update_attributes :name => 'Beth' } # this syntax also works
|
||||||
|
>> widget.versions.last.whodunnit # Ben Atkins
|
||||||
|
```
|
||||||
|
|
||||||
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`.
|
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.
|
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.
|
||||||
|
@ -1062,6 +1079,7 @@ Many thanks to:
|
||||||
* [Vlad Bokov](https://github.com/razum2um)
|
* [Vlad Bokov](https://github.com/razum2um)
|
||||||
* [Sean Marcia](https://github.com/SeanMarcia)
|
* [Sean Marcia](https://github.com/SeanMarcia)
|
||||||
* [Chulki Lee](https://github.com/chulkilee)
|
* [Chulki Lee](https://github.com/chulkilee)
|
||||||
|
* [Lucas Souza](https://github.com/lucasas)
|
||||||
|
|
||||||
|
|
||||||
## Inspirations
|
## Inspirations
|
||||||
|
|
|
@ -14,11 +14,11 @@ module PaperTrail
|
||||||
# `:create`, `:update`, `:destroy` as desired.
|
# `:create`, `:update`, `:destroy` as desired.
|
||||||
# :class_name the name of a custom Version class. This class should inherit from `PaperTrail::Version`.
|
# :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.
|
# :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.
|
# 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
|
# :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
|
# :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.
|
# 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
|
# :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
|
# a new `Version`. In addition, these fields will not be included in the serialized versions
|
||||||
|
@ -216,6 +216,18 @@ module PaperTrail
|
||||||
self.class.paper_trail_on! if paper_trail_was_enabled
|
self.class.paper_trail_on! if paper_trail_was_enabled
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Temporarily overwrites the value of whodunnit and then executes the provided block.
|
||||||
|
def whodunnit(value)
|
||||||
|
raise ArgumentError, 'expected to receive a block' unless block_given?
|
||||||
|
current_whodunnit = PaperTrail.whodunnit
|
||||||
|
PaperTrail.whodunnit = value
|
||||||
|
begin
|
||||||
|
yield self
|
||||||
|
ensure
|
||||||
|
PaperTrail.whodunnit = current_whodunnit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Mimicks behavior of `touch` method from `ActiveRecord::Persistence`, but generates a version
|
# Mimicks behavior of `touch` method from `ActiveRecord::Persistence`, but generates a version
|
||||||
#
|
#
|
||||||
# TODO: lookinto leveraging the `after_touch` callback from `ActiveRecord` to allow the
|
# TODO: lookinto leveraging the `after_touch` callback from `ActiveRecord` to allow the
|
||||||
|
|
|
@ -23,6 +23,39 @@ describe Widget do
|
||||||
|
|
||||||
describe "Methods" do
|
describe "Methods" do
|
||||||
describe "Instance", :versioning => true do
|
describe "Instance", :versioning => true do
|
||||||
|
describe :whodunnit do
|
||||||
|
it { should respond_to(:whodunnit) }
|
||||||
|
|
||||||
|
context "no block given" do
|
||||||
|
it "should raise an error" do
|
||||||
|
expect { widget.whodunnit('Ben') }.to raise_error(ArgumentError, 'expected to receive a block')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "block given" do
|
||||||
|
let(:orig_name) { Faker::Name.name }
|
||||||
|
let(:new_name) { Faker::Name.name }
|
||||||
|
|
||||||
|
before do
|
||||||
|
PaperTrail.whodunnit = orig_name
|
||||||
|
widget.versions.last.whodunnit.should == orig_name # persist `widget`
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should modify value of `PaperTrail.whodunnit` while executing the block" do
|
||||||
|
widget.whodunnit(new_name) do
|
||||||
|
PaperTrail.whodunnit.should == new_name
|
||||||
|
widget.update_attributes(:name => 'Elizabeth')
|
||||||
|
end
|
||||||
|
widget.versions.last.whodunnit.should == new_name
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should revert the value of `PaperTrail.whodunnit` to it's previous value after executing the block" do
|
||||||
|
widget.whodunnit(new_name) { |w| w.update_attributes(:name => 'Elizabeth') }
|
||||||
|
PaperTrail.whodunnit.should == orig_name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe :touch_with_version do
|
describe :touch_with_version do
|
||||||
it { should respond_to(:touch_with_version) }
|
it { should respond_to(:touch_with_version) }
|
||||||
|
|
||||||
|
|
|
@ -771,7 +771,7 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
||||||
should 'store dynamic meta data based on a method of the item' do
|
should 'store dynamic meta data based on a method of the item' do
|
||||||
assert_equal @article.action_data_provider_method, @article.versions.last.action
|
assert_equal @article.action_data_provider_method, @article.versions.last.action
|
||||||
end
|
end
|
||||||
|
|
||||||
should 'store dynamic meta data based on an attribute of the item prior to creation' do
|
should 'store dynamic meta data based on an attribute of the item prior to creation' do
|
||||||
assert_equal nil, @article.versions.last.title
|
assert_equal nil, @article.versions.last.title
|
||||||
end
|
end
|
||||||
|
@ -793,7 +793,7 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
||||||
should 'store dynamic meta data which depends on the item' do
|
should 'store dynamic meta data which depends on the item' do
|
||||||
assert_equal @article.id, @article.versions.last.article_id
|
assert_equal @article.id, @article.versions.last.article_id
|
||||||
end
|
end
|
||||||
|
|
||||||
should 'store dynamic meta data based on an attribute of the item prior to the update' do
|
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
|
assert_equal @initial_title, @article.versions.last.title
|
||||||
end
|
end
|
||||||
|
@ -814,7 +814,7 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
||||||
should 'store dynamic meta data which depends on the item' do
|
should 'store dynamic meta data which depends on the item' do
|
||||||
assert_equal @article.id, @article.versions.last.article_id
|
assert_equal @article.id, @article.versions.last.article_id
|
||||||
end
|
end
|
||||||
|
|
||||||
should 'store dynamic meta data based on an attribute of the item prior to the destruction' do
|
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
|
assert_equal @initial_title, @article.versions.last.title
|
||||||
end
|
end
|
||||||
|
@ -837,7 +837,6 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
||||||
should 'return its previous self' do
|
should 'return its previous self' do
|
||||||
assert_equal @widget.versions[-2].reify, @widget.previous_version
|
assert_equal @widget.versions[-2].reify, @widget.previous_version
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue