Integrate versioning into AR touch method (#1063)
* integrate versioning into AR touch method * add touch to list of :on events, deprecate touch_with_version * integrate versioning into AR touch method
This commit is contained in:
parent
87f097c05f
commit
02b6de2dac
|
@ -25,12 +25,14 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/).
|
|||
|
||||
### Deprecated
|
||||
|
||||
- [#1063](https://github.com/airblade/paper_trail/pull/1063) - `touch_with_version` is deprecated in favor of using the original AR `touch` method
|
||||
- [#1033](https://github.com/airblade/paper_trail/pull/1033) - Request variables
|
||||
are now set using eg. `PaperTrail.request.whodunnit=` and the old way,
|
||||
`PaperTrail.whodunnit=` is deprecated.
|
||||
|
||||
### Added
|
||||
|
||||
- [#1063](https://github.com/airblade/paper_trail/pull/1063) - AR `touch` method now creates a version if the `:on` option includes `touch`. By default it also includes the `touch` event now.
|
||||
- [#1033](https://github.com/airblade/paper_trail/pull/1033) -
|
||||
Set request variables temporarily using a block, eg.
|
||||
`PaperTrail.request(whodunnit: 'Jared') do .. end`
|
||||
|
|
23
README.md
23
README.md
|
@ -207,10 +207,6 @@ widget.paper_trail.previous_version
|
|||
# Returns the widget (not a version) as it became next.
|
||||
widget.paper_trail.next_version
|
||||
|
||||
# Generates a version for a `touch` event (`widget.touch` does NOT generate a
|
||||
# version)
|
||||
widget.paper_trail.touch_with_version
|
||||
|
||||
# Enable/disable PaperTrail, for Widget, for the current request (not all threads)
|
||||
PaperTrail.request.disable_model(Widget)
|
||||
PaperTrail.request.enable_model(Widget)
|
||||
|
@ -292,7 +288,7 @@ ignore `create` events:
|
|||
|
||||
```ruby
|
||||
class Article < ActiveRecord::Base
|
||||
has_paper_trail on: [:update, :destroy]
|
||||
has_paper_trail on: [:update, :destroy, :touch]
|
||||
end
|
||||
```
|
||||
|
||||
|
@ -337,6 +333,7 @@ class Article < ActiveRecord::Base
|
|||
paper_trail.on_destroy # add destroy callback
|
||||
paper_trail.on_update # etc.
|
||||
paper_trail.on_create
|
||||
paper_trail.on_touch
|
||||
end
|
||||
```
|
||||
|
||||
|
@ -706,6 +703,22 @@ sql> delete from versions where created_at < 2010-06-01;
|
|||
PaperTrail::Version.delete_all ['created_at < ?', 1.week.ago]
|
||||
```
|
||||
|
||||
### 3.e. Trigger Version creation
|
||||
|
||||
At some point you may want to trigger a new version to be created. To do this we utilize the AR `touch` method.
|
||||
|
||||
```ruby
|
||||
widget.touch
|
||||
```
|
||||
|
||||
The new versions event will be saved as `update`.
|
||||
|
||||
If you are using the `:on` option in your model you must specify the `touch` event also. For example:
|
||||
|
||||
```ruby
|
||||
has_paper_trail on: [:update, :destroy, :touch]
|
||||
```
|
||||
|
||||
## 4. Saving More Information About Versions
|
||||
|
||||
### 4.a. Finding Out Who Was Responsible For A Change
|
||||
|
|
|
@ -116,11 +116,19 @@ module PaperTrail
|
|||
@model_class.paper_trail_options[:on] << :update
|
||||
end
|
||||
|
||||
# Adds a callback that records a version after a "touch" event.
|
||||
# @api public
|
||||
def on_touch
|
||||
@model_class.after_touch { |r|
|
||||
r.paper_trail.record_update(force: true, in_after_callback: true)
|
||||
}
|
||||
end
|
||||
|
||||
# Set up `@model_class` for PaperTrail. Installs callbacks, associations,
|
||||
# "class attributes", instance methods, and more.
|
||||
# @api private
|
||||
def setup(options = {})
|
||||
options[:on] ||= %i[create update destroy]
|
||||
options[:on] ||= %i[create update destroy touch]
|
||||
options[:on] = Array(options[:on]) # Support single symbol
|
||||
@model_class.send :include, ::PaperTrail::Model::InstanceMethods
|
||||
setup_options(options)
|
||||
|
|
|
@ -7,6 +7,12 @@ module PaperTrail
|
|||
my_model_instance.paper_trail.whodunnit('John') is deprecated,
|
||||
please use PaperTrail.request(whodunnit: 'John')
|
||||
STR
|
||||
|
||||
DPR_TOUCH_WITH_VERSION = <<-STR.squish.freeze
|
||||
my_model_instance.paper_trail.touch_with_version is deprecated,
|
||||
please use my_model_instance.touch
|
||||
STR
|
||||
|
||||
RAILS_GTE_5_1 = ::ActiveRecord.gem_version >= ::Gem::Version.new("5.1.0.beta1")
|
||||
|
||||
def initialize(record)
|
||||
|
@ -461,8 +467,9 @@ module PaperTrail
|
|||
# version records are inserted. It's unclear under which specific
|
||||
# circumstances this technique should be adopted.
|
||||
#
|
||||
# @api public
|
||||
# @deprecated
|
||||
def touch_with_version(name = nil)
|
||||
::ActiveSupport::Deprecation.warn(DPR_TOUCH_WITH_VERSION, caller(1))
|
||||
unless @record.persisted?
|
||||
raise ::ActiveRecord::ActiveRecordError, "can not touch on a new record object"
|
||||
end
|
||||
|
@ -571,9 +578,8 @@ module PaperTrail
|
|||
if @in_after_callback
|
||||
@record.attribute_before_last_save(attr_name.to_s)
|
||||
else
|
||||
# Either we are doing a `touch_with_version` or `record_destroy`.
|
||||
# Other events, like `record_create`, can only be done in an
|
||||
# after-callback.
|
||||
# We are performing a `record_destroy`. Other events,
|
||||
# like `record_create`, can only be done in an after-callback.
|
||||
@record.attribute_in_database(attr_name.to_s)
|
||||
end
|
||||
else
|
||||
|
|
|
@ -189,9 +189,12 @@ RSpec.describe Article, type: :model, versioning: true do
|
|||
describe "#touch_with_version" do
|
||||
it "creates a version, ignoring the :only option" do
|
||||
article = described_class.create
|
||||
|
||||
allow(::ActiveSupport::Deprecation).to receive(:warn)
|
||||
expect { article.paper_trail.touch_with_version }.to change {
|
||||
::PaperTrail::Version.count
|
||||
}.by(+1)
|
||||
expect(::ActiveSupport::Deprecation).to have_received(:warn).once
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -67,7 +67,7 @@ RSpec.describe CallbackModifier, type: :model, versioning: true do
|
|||
context "when no callback-method used" do
|
||||
it "sets paper_trail_options[:on] to [:create, :update, :destroy]" do
|
||||
modifier = DefaultModifier.create!(some_content: FFaker::Lorem.sentence)
|
||||
expect(modifier.paper_trail_options[:on]).to eq %i[create update destroy]
|
||||
expect(modifier.paper_trail_options[:on]).to eq %i[create update destroy touch]
|
||||
end
|
||||
|
||||
it "tracks destroy" do
|
||||
|
|
|
@ -7,17 +7,21 @@ RSpec.describe NotOnUpdate, type: :model do
|
|||
let!(:record) { described_class.create! }
|
||||
|
||||
it "creates a version, regardless" do
|
||||
allow(::ActiveSupport::Deprecation).to receive(:warn)
|
||||
expect { record.paper_trail.touch_with_version }.to change {
|
||||
PaperTrail::Version.count
|
||||
}.by(+1)
|
||||
expect(::ActiveSupport::Deprecation).to have_received(:warn).once
|
||||
end
|
||||
|
||||
it "increments the `:updated_at` timestamp" do
|
||||
before = record.updated_at
|
||||
allow(::ActiveSupport::Deprecation).to receive(:warn)
|
||||
# Travel 1 second because MySQL lacks sub-second resolution
|
||||
Timecop.travel(1) do
|
||||
record.paper_trail.touch_with_version
|
||||
end
|
||||
expect(::ActiveSupport::Deprecation).to have_received(:warn).once
|
||||
expect(record.updated_at).to be > before
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,7 +15,9 @@ module On
|
|||
describe "#touch_with_version" do
|
||||
it "creates a version record" do
|
||||
record = described_class.create(name: "Alice")
|
||||
allow(::ActiveSupport::Deprecation).to receive(:warn)
|
||||
record.paper_trail.touch_with_version
|
||||
expect(::ActiveSupport::Deprecation).to have_received(:warn).once
|
||||
expect(record.versions.length).to(eq(1))
|
||||
v = record.versions.first
|
||||
expect(v.event).to(eq("update"))
|
||||
|
|
|
@ -25,5 +25,13 @@ module On
|
|||
expect(record.versions.last.event).to(eq("banana"))
|
||||
end
|
||||
end
|
||||
|
||||
describe "#touch" do
|
||||
it "does not create a version for the touch event" do
|
||||
record = described_class.create(name: "Alice")
|
||||
count = record.versions.count
|
||||
expect(count).to eq(count)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -37,7 +37,9 @@ RSpec.describe PostWithStatus, type: :model do
|
|||
expect(post.versions.count).to eq(1)
|
||||
expect(post.status).to eq("draft")
|
||||
Timecop.travel 1.second.since # because MySQL lacks fractional seconds precision
|
||||
allow(::ActiveSupport::Deprecation).to receive(:warn)
|
||||
post.paper_trail.touch_with_version
|
||||
expect(::ActiveSupport::Deprecation).to have_received(:warn).once
|
||||
expect(post.versions.count).to eq(2)
|
||||
expect(post.versions.last[:object]).to include("status: 0")
|
||||
expect(post.paper_trail.previous_version.status).to eq("draft")
|
||||
|
|
|
@ -232,21 +232,40 @@ RSpec.describe Widget, type: :model do
|
|||
|
||||
describe "#touch_with_version", versioning: true do
|
||||
it "creates a version" do
|
||||
allow(::ActiveSupport::Deprecation).to receive(:warn)
|
||||
count = widget.versions.size
|
||||
# Travel 1 second because MySQL lacks sub-second resolution
|
||||
Timecop.travel(1) do
|
||||
widget.paper_trail.touch_with_version
|
||||
end
|
||||
expect(widget.versions.size).to eq(count + 1)
|
||||
expect(::ActiveSupport::Deprecation).to have_received(:warn).once
|
||||
end
|
||||
|
||||
it "increments the `:updated_at` timestamp" do
|
||||
allow(::ActiveSupport::Deprecation).to receive(:warn)
|
||||
time_was = widget.updated_at
|
||||
# Travel 1 second because MySQL lacks sub-second resolution
|
||||
Timecop.travel(1) do
|
||||
widget.paper_trail.touch_with_version
|
||||
end
|
||||
expect(widget.updated_at).to be > time_was
|
||||
expect(::ActiveSupport::Deprecation).to have_received(:warn).once
|
||||
end
|
||||
end
|
||||
|
||||
describe "touch", versioning: true do
|
||||
it "creates a version" do
|
||||
expect { widget.touch }.to change {
|
||||
widget.versions.count
|
||||
}.by(+1)
|
||||
end
|
||||
|
||||
it "does not create a version using without_versioning" do
|
||||
count = widget.versions.count
|
||||
widget.paper_trail.without_versioning do
|
||||
widget.touch
|
||||
end
|
||||
expect(count).to eq(count)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -56,15 +56,15 @@ RSpec.describe(::PaperTrail, versioning: true) do
|
|||
context "and then updated without any changes" do
|
||||
before { @widget.touch }
|
||||
|
||||
it "not have a new version" do
|
||||
expect(@widget.versions.length).to(eq(1))
|
||||
it "to have two previous versions" do
|
||||
expect(@widget.versions.length).to(eq(2))
|
||||
end
|
||||
end
|
||||
|
||||
context "and then updated with changes" do
|
||||
before { @widget.update_attributes(name: "Harry") }
|
||||
|
||||
it "have two previous versions" do
|
||||
it "have three previous versions" do
|
||||
expect(@widget.versions.length).to(eq(2))
|
||||
end
|
||||
|
||||
|
@ -381,7 +381,9 @@ RSpec.describe(::PaperTrail, versioning: true) do
|
|||
|
||||
context "given a symbol, specifying a method name" do
|
||||
it "does not create a new version" do
|
||||
allow(::ActiveSupport::Deprecation).to receive(:warn)
|
||||
@widget.paper_trail.without_versioning(:touch_with_version)
|
||||
expect(::ActiveSupport::Deprecation).to have_received(:warn).once
|
||||
expect(@widget.versions.length).to(eq(@count))
|
||||
expect(::PaperTrail.request.enabled_for_model?(Widget)).to eq(true)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue