From 8cd1426b01f42be20890b77b30257937b46e77de Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Fri, 7 Mar 2014 16:06:18 -0500 Subject: [PATCH 01/12] Add generator spec for InstallGenerator; Use 'change' method for migrations --- .../add_object_changes_column_to_versions.rb | 6 +- .../paper_trail/templates/create_versions.rb | 7 +- paper_trail.gemspec | 1 + spec/generators/install_generator_spec.rb | 67 +++++++++++++++++++ 4 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 spec/generators/install_generator_spec.rb diff --git a/lib/generators/paper_trail/templates/add_object_changes_column_to_versions.rb b/lib/generators/paper_trail/templates/add_object_changes_column_to_versions.rb index f4674c48..68b19834 100644 --- a/lib/generators/paper_trail/templates/add_object_changes_column_to_versions.rb +++ b/lib/generators/paper_trail/templates/add_object_changes_column_to_versions.rb @@ -1,9 +1,5 @@ class AddObjectChangesColumnToVersions < ActiveRecord::Migration - def self.up + def change add_column :versions, :object_changes, :text end - - def self.down - remove_column :versions, :object_changes - end end diff --git a/lib/generators/paper_trail/templates/create_versions.rb b/lib/generators/paper_trail/templates/create_versions.rb index 701f7ea7..23be970c 100644 --- a/lib/generators/paper_trail/templates/create_versions.rb +++ b/lib/generators/paper_trail/templates/create_versions.rb @@ -1,5 +1,5 @@ class CreateVersions < ActiveRecord::Migration - def self.up + def change create_table :versions do |t| t.string :item_type, :null => false t.integer :item_id, :null => false @@ -10,9 +10,4 @@ class CreateVersions < ActiveRecord::Migration end add_index :versions, [:item_type, :item_id] end - - def self.down - remove_index :versions, [:item_type, :item_id] - drop_table :versions - end end diff --git a/paper_trail.gemspec b/paper_trail.gemspec index 9025243c..6418db03 100644 --- a/paper_trail.gemspec +++ b/paper_trail.gemspec @@ -30,6 +30,7 @@ Gem::Specification.new do |s| s.add_development_dependency 'sinatra', '~> 1.0' s.add_development_dependency 'rack-test', '>= 0.6' s.add_development_dependency 'rspec-rails', '~> 2.14' + s.add_development_dependency 'generator_spec' # JRuby support for the test ENV unless defined?(JRUBY_VERSION) diff --git a/spec/generators/install_generator_spec.rb b/spec/generators/install_generator_spec.rb new file mode 100644 index 00000000..e40ca199 --- /dev/null +++ b/spec/generators/install_generator_spec.rb @@ -0,0 +1,67 @@ +require 'spec_helper' +require 'generator_spec/test_case' +require File.expand_path('../../../lib/generators/paper_trail/install_generator', __FILE__) + +describe PaperTrail::InstallGenerator, :type => :generator do + include GeneratorSpec::TestCase + destination File.expand_path('../tmp', __FILE__) + + after(:all) { prepare_destination } # cleanup the tmp directory + + describe "no options" do + before(:all) do + prepare_destination + run_generator + end + + it "generates a migration for creating the 'versions' table" do + destination_root.should have_structure { + directory 'db' do + directory 'migrate' do + migration 'create_versions' do + contains 'class CreateVersions' + contains 'def change' + contains 'create_table :versions do |t|' + end + end + end + } + end + end + + describe "`--with-changes` option set to `true`" do + before(:all) do + prepare_destination + run_generator %w(--with-changes) + end + + it "generates a migration for creating the 'versions' table" do + destination_root.should have_structure { + directory 'db' do + directory 'migrate' do + migration 'create_versions' do + contains 'class CreateVersions' + contains 'def change' + contains 'create_table :versions do |t|' + end + end + end + } + end + + it "generates a migration for adding the 'object_changes' column to the 'versions' table" do + destination_root.should have_structure { + directory 'db' do + directory 'migrate' do + migration 'add_object_changes_column_to_versions' do + contains 'class AddObjectChangesColumnToVersions' + contains 'def change' + contains 'add_column :versions, :object_changes, :text' + end + end + end + } + end + end + +end From 72f5215c69002cb1f8b6171d67b4a6e86014932e Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Fri, 7 Mar 2014 16:13:32 -0500 Subject: [PATCH 02/12] close #340; Remove unnecessary require statement from InstallGenerator --- CHANGELOG.md | 2 ++ lib/generators/paper_trail/install_generator.rb | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f6df0d3..b9f2be50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## 3.0.1 (Unreleased) + - [#340](https://github.com/airblade/paper_trail/issues/340) - Prevent potential error encountered when using the `InstallGenerator` + with Rails `4.1.0.rc1`. - [#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. - [#328](https://github.com/airblade/paper_trail/pull/328) / [#326](https://github.com/airblade/paper_trail/issues/326)/ diff --git a/lib/generators/paper_trail/install_generator.rb b/lib/generators/paper_trail/install_generator.rb index 2b78b97b..e35db478 100644 --- a/lib/generators/paper_trail/install_generator.rb +++ b/lib/generators/paper_trail/install_generator.rb @@ -1,5 +1,4 @@ require 'rails/generators' -require 'rails/generators/migration' require 'rails/generators/active_record' module PaperTrail From c0bf77991a1d155b4af9c1eb35f4506a8591f852 Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Fri, 7 Mar 2014 16:26:41 -0500 Subject: [PATCH 03/12] Add 'generator_spec' gem to rails3 Gemfile for Travis; use :fast_finish option on Travis --- .travis.yml | 1 + gemfiles/3.0.gemfile | 1 + 2 files changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 6dbe886b..3c9e6e33 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ gemfile: - gemfiles/3.0.gemfile matrix: + fast_finish: true allow_failures: - rvm: jruby-18mode gemfile: Gemfile diff --git a/gemfiles/3.0.gemfile b/gemfiles/3.0.gemfile index 6f2f0811..4f33a833 100644 --- a/gemfiles/3.0.gemfile +++ b/gemfiles/3.0.gemfile @@ -19,6 +19,7 @@ group :development, :test do # RSpec testing gem 'rspec-rails', '~> 2.14' + gem 'generator_spec' platforms :jruby, :ruby_18 do # shoulda-matchers > 2.0 is not compatible with Ruby18. From ed2e3d55e43b108a18eaaee29bd205c760fbd3ef Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Fri, 7 Mar 2014 16:28:04 -0500 Subject: [PATCH 04/12] Remove word 'column' from migration to add 'object_changes' column to follow Rails convention --- lib/generators/paper_trail/install_generator.rb | 2 +- ...olumn_to_versions.rb => add_object_changes_to_versions.rb} | 2 +- spec/generators/install_generator_spec.rb | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename lib/generators/paper_trail/templates/{add_object_changes_column_to_versions.rb => add_object_changes_to_versions.rb} (52%) diff --git a/lib/generators/paper_trail/install_generator.rb b/lib/generators/paper_trail/install_generator.rb index e35db478..8c8c8e14 100644 --- a/lib/generators/paper_trail/install_generator.rb +++ b/lib/generators/paper_trail/install_generator.rb @@ -12,7 +12,7 @@ module PaperTrail def create_migration_file migration_template 'create_versions.rb', 'db/migrate/create_versions.rb' - migration_template 'add_object_changes_column_to_versions.rb', 'db/migrate/add_object_changes_column_to_versions.rb' if options.with_changes? + migration_template 'add_object_changes_to_versions.rb', 'db/migrate/add_object_changes_to_versions.rb' if options.with_changes? end def self.next_migration_number(dirname) diff --git a/lib/generators/paper_trail/templates/add_object_changes_column_to_versions.rb b/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb similarity index 52% rename from lib/generators/paper_trail/templates/add_object_changes_column_to_versions.rb rename to lib/generators/paper_trail/templates/add_object_changes_to_versions.rb index 68b19834..2d723e06 100644 --- a/lib/generators/paper_trail/templates/add_object_changes_column_to_versions.rb +++ b/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb @@ -1,4 +1,4 @@ -class AddObjectChangesColumnToVersions < ActiveRecord::Migration +class AddObjectChangesToVersions < ActiveRecord::Migration def change add_column :versions, :object_changes, :text end diff --git a/spec/generators/install_generator_spec.rb b/spec/generators/install_generator_spec.rb index e40ca199..298217ed 100644 --- a/spec/generators/install_generator_spec.rb +++ b/spec/generators/install_generator_spec.rb @@ -53,8 +53,8 @@ describe PaperTrail::InstallGenerator, :type => :generator do destination_root.should have_structure { directory 'db' do directory 'migrate' do - migration 'add_object_changes_column_to_versions' do - contains 'class AddObjectChangesColumnToVersions' + migration 'add_object_changes_to_versions' do + contains 'class AddObjectChangesToVersions' contains 'def change' contains 'add_column :versions, :object_changes, :text' end From 52823d2fb2af035c03d789a4e8a2419312174bb4 Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Tue, 11 Mar 2014 10:48:06 -0400 Subject: [PATCH 05/12] close #312; Fix RSpec 'with_versioning' class helper method --- CHANGELOG.md | 1 + lib/paper_trail/frameworks/rspec.rb | 5 ++-- .../frameworks/rspec/extensions.rb | 20 -------------- lib/paper_trail/frameworks/rspec/helpers.rb | 27 +++++++++++++++++++ spec/paper_trail_spec.rb | 15 ++++++++++- 5 files changed, 45 insertions(+), 23 deletions(-) delete mode 100644 lib/paper_trail/frameworks/rspec/extensions.rb create mode 100644 lib/paper_trail/frameworks/rspec/helpers.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index b9f2be50..4cdee792 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ instead of `current_user` (if `current_user` is defined). - [#313](https://github.com/airblade/paper_trail/pull/313) - Make the `Rails::Controller` helper compatible with `ActionController::API` for compatibility with the [`rails-api`](https://github.com/rails-api/rails-api) gem. + - [#312](https://github.com/airblade/paper_trail/issues/312) - Fix RSpec `with_versioning` class level helper method. - Deprecated `Model.paper_trail_on` and `Model.paper_trail_off` in favor of bang versions of the methods. Deprecation warning informs users that the non-bang versions of the methods will be removed in version `3.1.0`. diff --git a/lib/paper_trail/frameworks/rspec.rb b/lib/paper_trail/frameworks/rspec.rb index 174a9992..564208c6 100644 --- a/lib/paper_trail/frameworks/rspec.rb +++ b/lib/paper_trail/frameworks/rspec.rb @@ -1,9 +1,10 @@ require 'rspec/core' require 'rspec/matchers' -require File.expand_path('../rspec/extensions', __FILE__) +require 'paper_trail/frameworks/rspec/helpers' RSpec.configure do |config| - config.include ::PaperTrail::RSpec::Extensions + config.include ::PaperTrail::RSpec::Helpers::InstanceMethods + config.extend ::PaperTrail::RSpec::Helpers::ClassMethods config.before(:each) do ::PaperTrail.enabled = false diff --git a/lib/paper_trail/frameworks/rspec/extensions.rb b/lib/paper_trail/frameworks/rspec/extensions.rb deleted file mode 100644 index c2149918..00000000 --- a/lib/paper_trail/frameworks/rspec/extensions.rb +++ /dev/null @@ -1,20 +0,0 @@ -module PaperTrail - module RSpec - module Extensions - # :call-seq: - # with_versioning - # - # enable versioning for specific blocks - - def with_versioning - was_enabled = ::PaperTrail.enabled? - ::PaperTrail.enabled = true - begin - yield - ensure - ::PaperTrail.enabled = was_enabled - end - end - end - end -end diff --git a/lib/paper_trail/frameworks/rspec/helpers.rb b/lib/paper_trail/frameworks/rspec/helpers.rb new file mode 100644 index 00000000..eabfba99 --- /dev/null +++ b/lib/paper_trail/frameworks/rspec/helpers.rb @@ -0,0 +1,27 @@ +module PaperTrail + module RSpec + module Helpers + module InstanceMethods + # enable versioning for specific blocks (at instance-level) + def with_versioning + was_enabled = ::PaperTrail.enabled? + ::PaperTrail.enabled = true + begin + yield + ensure + ::PaperTrail.enabled = was_enabled + end + end + end + + module ClassMethods + # enable versioning for specific blocks (at class-level) + def with_versioning(&block) + context 'with versioning', :versioning => true do + class_exec(&block) + end + end + end + end + end +end diff --git a/spec/paper_trail_spec.rb b/spec/paper_trail_spec.rb index e238fddb..d9dd4146 100644 --- a/spec/paper_trail_spec.rb +++ b/spec/paper_trail_spec.rb @@ -5,7 +5,7 @@ describe "PaperTrail RSpec Helper" do it 'should have versioning off by default' do ::PaperTrail.should_not be_enabled end - it 'should turn versioning on in a with_versioning block' do + it 'should turn versioning on in a `with_versioning` block' do ::PaperTrail.should_not be_enabled with_versioning do ::PaperTrail.should be_enabled @@ -27,6 +27,19 @@ describe "PaperTrail RSpec Helper" do end end + context '`with_versioning` block at class level' do + it { ::PaperTrail.should_not be_enabled } + + with_versioning do + it 'should have versioning on by default' do + ::PaperTrail.should be_enabled + end + end + it 'should not leak the `enabled?` state into successive tests' do + ::PaperTrail.should_not be_enabled + end + end + describe :whodunnit do before(:all) { ::PaperTrail.whodunnit = 'foobar' } From 44a632eea6831fc4cc87b67772f782d5e670a27d Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Tue, 11 Mar 2014 17:55:44 -0400 Subject: [PATCH 06/12] close #334; Add small-scope 'whodunnit' method to PaperTrail::Model::InstanceMethods --- CHANGELOG.md | 3 ++- README.md | 30 +++++++++++++++++++++------ lib/paper_trail/has_paper_trail.rb | 16 +++++++++++++-- spec/models/widget_spec.rb | 33 ++++++++++++++++++++++++++++++ test/unit/model_test.rb | 7 +++---- 5 files changed, 76 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cdee792..5b4911a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,10 @@ - [#340](https://github.com/airblade/paper_trail/issues/340) - Prevent potential error encountered when using the `InstallGenerator` 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`, 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 `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)` diff --git a/README.md b/README.md index 50aaddf7..e70c07c5 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: @@ -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: ```ruby -class PaperTrail::Version < ActiveRecord::Base - if defined?(Rails::Console) - PaperTrail.whodunnit = "#{`whoami`.strip}: console" - elsif File.basename($0) == "rake" - PaperTrail.whodunnit = "#{`whoami`.strip}: rake #{ARGV.join ' '}" +# config/initializers/paper_trail.rb +module PaperTrail + class Version < ActiveRecord::Base + if defined?(Rails::Console) + PaperTrail.whodunnit = "#{`whoami`.strip}: console" + elsif File.basename($0) == "rake" + PaperTrail.whodunnit = "#{`whoami`.strip}: rake #{ARGV.join ' '}" + 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`. 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) * [Sean Marcia](https://github.com/SeanMarcia) * [Chulki Lee](https://github.com/chulkilee) +* [Lucas Souza](https://github.com/lucasas) ## Inspirations diff --git a/lib/paper_trail/has_paper_trail.rb b/lib/paper_trail/has_paper_trail.rb index e1103c73..2c0a210b 100644 --- a/lib/paper_trail/has_paper_trail.rb +++ b/lib/paper_trail/has_paper_trail.rb @@ -14,11 +14,11 @@ module PaperTrail # `: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 @@ -216,6 +216,18 @@ module PaperTrail self.class.paper_trail_on! if paper_trail_was_enabled 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 # # TODO: lookinto leveraging the `after_touch` callback from `ActiveRecord` to allow the diff --git a/spec/models/widget_spec.rb b/spec/models/widget_spec.rb index 0d951ba7..152d915e 100644 --- a/spec/models/widget_spec.rb +++ b/spec/models/widget_spec.rb @@ -23,6 +23,39 @@ describe Widget do describe "Methods" 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 it { should respond_to(:touch_with_version) } diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index 27983f47..09ef0727 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -771,7 +771,7 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase 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 +793,7 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase 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 +814,7 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase 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 @@ -837,7 +837,6 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase should 'return its previous self' do assert_equal @widget.versions[-2].reify, @widget.previous_version end - end From 5aea822771c77766f673f8abe4602c3b316d9e8b Mon Sep 17 00:00:00 2001 From: Kamil Kieliszczyk Date: Wed, 12 Mar 2014 10:03:32 +0100 Subject: [PATCH 07/12] Update "Has-One Associations" section in README [ci skip] --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index e70c07c5..8881d683 100644 --- a/README.md +++ b/README.md @@ -597,8 +597,14 @@ If you can think of a good way to achieve this, please let me know. PaperTrail can restore `:has_one` associations as they were at (actually, 3 seconds before) the time. ```ruby +class Location < ActiveRecord::Base + belongs_to :treasure + has_paper_trail +end + class Treasure < ActiveRecord::Base has_one :location + has_paper_trail end >> treasure.amount # 100 From 29cdfef414ebeb6b38e515b2d4ce8144ac26b505 Mon Sep 17 00:00:00 2001 From: Kamil Kieliszczyk Date: Wed, 12 Mar 2014 11:48:54 +0100 Subject: [PATCH 08/12] Fix PaperTrail initializer for setting console author [ci skip] Without that change the initializer does not work. It tries to find PaperTrail::Rails::Console instead of Rails::Console --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8881d683..a979a34c 100644 --- a/README.md +++ b/README.md @@ -483,7 +483,7 @@ You can avoid having to do this manually by setting your initializer to pick up # config/initializers/paper_trail.rb module PaperTrail class Version < ActiveRecord::Base - if defined?(Rails::Console) + if defined?(::Rails::Console) PaperTrail.whodunnit = "#{`whoami`.strip}: console" elsif File.basename($0) == "rake" PaperTrail.whodunnit = "#{`whoami`.strip}: rake #{ARGV.join ' '}" From 10d8451d70316edbf75ee10e717cb042af9e3519 Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Wed, 12 Mar 2014 09:40:20 -0400 Subject: [PATCH 09/12] Clarify README instructions for usage of ProtectedAttributes with metadata [ci skip] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a979a34c..a2e19014 100644 --- a/README.md +++ b/README.md @@ -719,7 +719,7 @@ PaperTrail will call your proc with the current article and store the result in N.B. You must also: * Add your metadata columns to the `versions` table. -* Declare your metadata columns using `attr_accessible`. (If you are using `Rails 3`, or `Rails 4` with the [ProtectedAttributes](https://github.com/rails/protected_attributes) gem) +* Declare your metadata columns using `attr_accessible`. (If you are using `ActiveRecord 3`, or `ActiveRecord 4` with the [ProtectedAttributes](https://github.com/rails/protected_attributes) gem) For example: From a9bb8ddf1b9c92e89a5a08e2c48d228c76aad343 Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Wed, 12 Mar 2014 09:53:17 -0400 Subject: [PATCH 10/12] Refactor instructions for initializer to automatically defer whodunnit value from shell [ci skip] --- README.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a2e19014..7198ed9d 100644 --- a/README.md +++ b/README.md @@ -481,14 +481,10 @@ You can avoid having to do this manually by setting your initializer to pick up ```ruby # config/initializers/paper_trail.rb -module PaperTrail - class Version < ActiveRecord::Base - if defined?(::Rails::Console) - PaperTrail.whodunnit = "#{`whoami`.strip}: console" - elsif File.basename($0) == "rake" - PaperTrail.whodunnit = "#{`whoami`.strip}: rake #{ARGV.join ' '}" - end - end +if defined?(::Rails::Console) + PaperTrail.whodunnit = "#{`whoami`.strip}: console" +elsif File.basename($0) == "rake" + PaperTrail.whodunnit = "#{`whoami`.strip}: rake #{ARGV.join ' '}" end ``` From 5302f5ecc86a85a5c7da42f1b031b68d84886ba8 Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Wed, 12 Mar 2014 10:09:59 -0400 Subject: [PATCH 11/12] Code condensation; 'without_versioning' method now yields model instance --- CHANGELOG.md | 2 ++ lib/paper_trail/frameworks/rspec/helpers.rb | 8 +++----- lib/paper_trail/has_paper_trail.rb | 10 ++++------ spec/models/widget_spec.rb | 7 +++++++ spec/paper_trail_spec.rb | 8 ++++++++ test/unit/model_test.rb | 16 +++++++++++++++- 6 files changed, 39 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b4911a1..f7244c5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ - [#313](https://github.com/airblade/paper_trail/pull/313) - Make the `Rails::Controller` helper compatible with `ActionController::API` for compatibility with the [`rails-api`](https://github.com/rails-api/rails-api) gem. - [#312](https://github.com/airblade/paper_trail/issues/312) - Fix RSpec `with_versioning` class level helper method. + - `model_instance.without_versioning` now yields the `model_instance`, enabling syntax like this: + `model_instance.without_versioning { |obj| obj.update_attributes(:name => 'value') }`. - Deprecated `Model.paper_trail_on` and `Model.paper_trail_off` in favor of bang versions of the methods. Deprecation warning informs users that the non-bang versions of the methods will be removed in version `3.1.0`. diff --git a/lib/paper_trail/frameworks/rspec/helpers.rb b/lib/paper_trail/frameworks/rspec/helpers.rb index eabfba99..63eab98f 100644 --- a/lib/paper_trail/frameworks/rspec/helpers.rb +++ b/lib/paper_trail/frameworks/rspec/helpers.rb @@ -6,11 +6,9 @@ module PaperTrail def with_versioning was_enabled = ::PaperTrail.enabled? ::PaperTrail.enabled = true - begin - yield - ensure - ::PaperTrail.enabled = was_enabled - end + yield + ensure + ::PaperTrail.enabled = was_enabled end end diff --git a/lib/paper_trail/has_paper_trail.rb b/lib/paper_trail/has_paper_trail.rb index 2c0a210b..a815f35a 100644 --- a/lib/paper_trail/has_paper_trail.rb +++ b/lib/paper_trail/has_paper_trail.rb @@ -211,7 +211,7 @@ module PaperTrail def without_versioning(method = nil) paper_trail_was_enabled = self.paper_trail_enabled_for_model? self.class.paper_trail_off! - method ? method.to_proc.call(self) : yield + method ? method.to_proc.call(self) : yield(self) ensure self.class.paper_trail_on! if paper_trail_was_enabled end @@ -221,11 +221,9 @@ module PaperTrail 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 + yield self + ensure + PaperTrail.whodunnit = current_whodunnit end # Mimicks behavior of `touch` method from `ActiveRecord::Persistence`, but generates a version diff --git a/spec/models/widget_spec.rb b/spec/models/widget_spec.rb index 152d915e..4184724b 100644 --- a/spec/models/widget_spec.rb +++ b/spec/models/widget_spec.rb @@ -53,6 +53,13 @@ describe Widget do widget.whodunnit(new_name) { |w| w.update_attributes(:name => 'Elizabeth') } PaperTrail.whodunnit.should == orig_name end + + context "error within block" do + it "should ensure that the whodunnit value still reverts to it's previous value" do + expect { widget.whodunnit(new_name) { raise } }.to raise_error + PaperTrail.whodunnit.should == orig_name + end + end end end diff --git a/spec/paper_trail_spec.rb b/spec/paper_trail_spec.rb index d9dd4146..97f34d84 100644 --- a/spec/paper_trail_spec.rb +++ b/spec/paper_trail_spec.rb @@ -12,6 +12,14 @@ describe "PaperTrail RSpec Helper" do end ::PaperTrail.should_not be_enabled end + + context "error within `with_versioning` block" do + it "should revert the value of `PaperTrail.enabled?` to it's previous state" do + ::PaperTrail.should_not be_enabled + expect { with_versioning { raise } }.to raise_error + ::PaperTrail.should_not be_enabled + end + end end context '`versioning: true`', :versioning => true do diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index 09ef0727..81a97ec0 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -515,10 +515,24 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase @widget.without_versioning do @widget.update_attributes :name => 'Ford' end + # The model instance should yield itself for convenience purposes + @widget.without_versioning { |w| w.update_attributes :name => 'Nixon' } end should 'not create new version' do - assert_equal 1, @widget.versions.length + assert_equal @count, @widget.versions.length + end + + should 'enable paper trail after call' do + assert Widget.paper_trail_enabled_for_model? + end + end + + context 'when receiving a method name as an argument' do + setup { @widget.without_versioning(:touch_with_version) } + + should 'not create new version' do + assert_equal @count, @widget.versions.length end should 'enable paper trail after call' do From 12a9ca9b313507e3338a3aa4489a6c002b7a9930 Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Wed, 12 Mar 2014 15:02:34 -0400 Subject: [PATCH 12/12] Adjust language in README for abstract class declaration; rename key assignment appropriately for PaperTrail.enabled_for_model --- README.md | 2 +- lib/paper_trail.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7198ed9d..6338adad 100644 --- a/README.md +++ b/README.md @@ -553,7 +553,7 @@ Alternatively you could store certain metadata for one type of version, and othe If you only use custom version classes and don't use PaperTrail's built-in one, on Rails `>= 3.2` you must: -- either declare PaperTrail's version class abstract like this (in `config/initializers/paper_trail_patch.rb`): +- either declare the `PaperTrail::Version` class to be abstract like this (in an initializer): ```ruby PaperTrail::Version.module_eval do diff --git a/lib/paper_trail.rb b/lib/paper_trail.rb index 8f0e78aa..9c68bd41 100644 --- a/lib/paper_trail.rb +++ b/lib/paper_trail.rb @@ -34,12 +34,12 @@ module PaperTrail # Sets whether PaperTrail is enabled or disabled for this model in the current request. def self.enabled_for_model(model, value) - paper_trail_store[:"request_enabled_for_#{model}"] = value + paper_trail_store[:"enabled_for_#{model}"] = value end # Returns `true` if PaperTrail is enabled for this model in the current request, `false` otherwise. def self.enabled_for_model?(model) - !!paper_trail_store.fetch(:"request_enabled_for_#{model}", true) + !!paper_trail_store.fetch(:"enabled_for_#{model}", true) end # Set the field which records when a version was created.