Track changes on destroy (#1123)
this involved refactoring the internal serialization code so it'd be possible to run it on non-Rails-provided changes
This commit is contained in:
parent
40fa4c0b4b
commit
c145cc46c2
|
@ -31,6 +31,9 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/).
|
||||||
- [#1099](https://github.com/paper-trail-gem/paper_trail/issues/1099) -
|
- [#1099](https://github.com/paper-trail-gem/paper_trail/issues/1099) -
|
||||||
Ability to save ~50% storage space by making the `object` column optional.
|
Ability to save ~50% storage space by making the `object` column optional.
|
||||||
Note that this disables `reify` and `where_object`.
|
Note that this disables `reify` and `where_object`.
|
||||||
|
- `object_changes` is now populated on destroy in order to make
|
||||||
|
`where_object_changes` usable when you've dropped the `object` column.
|
||||||
|
See the issue for a backport migration.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
@ -119,14 +119,25 @@ module PaperTrail
|
||||||
end
|
end
|
||||||
|
|
||||||
# @api private
|
# @api private
|
||||||
def changes
|
def prepare_object_changes(changes)
|
||||||
notable_changes = changes_in_latest_version.delete_if { |k, _v|
|
changes = serialize_object_changes(changes)
|
||||||
!notably_changed.include?(k)
|
changes = recordable_object_changes(changes)
|
||||||
}
|
changes
|
||||||
|
end
|
||||||
|
|
||||||
|
# @api private
|
||||||
|
def serialize_object_changes(changes)
|
||||||
AttributeSerializers::ObjectChangesAttribute.
|
AttributeSerializers::ObjectChangesAttribute.
|
||||||
new(@record.class).
|
new(@record.class).
|
||||||
serialize(notable_changes)
|
serialize(changes)
|
||||||
notable_changes.to_hash
|
changes.to_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
# @api private
|
||||||
|
def notable_changes
|
||||||
|
changes_in_latest_version.delete_if { |k, _v|
|
||||||
|
!notably_changed.include?(k)
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Rails 5.1 changed the API of `ActiveRecord::Dirty`. See
|
# Rails 5.1 changed the API of `ActiveRecord::Dirty`. See
|
||||||
|
|
|
@ -20,7 +20,8 @@ module PaperTrail
|
||||||
data[:created_at] = @record.updated_at
|
data[:created_at] = @record.updated_at
|
||||||
end
|
end
|
||||||
if record_object_changes? && changed_notably?
|
if record_object_changes? && changed_notably?
|
||||||
data[:object_changes] = recordable_object_changes(changes)
|
changes = notable_changes
|
||||||
|
data[:object_changes] = prepare_object_changes(changes)
|
||||||
end
|
end
|
||||||
merge_metadata_into(data)
|
merge_metadata_into(data)
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,6 +21,11 @@ module PaperTrail
|
||||||
if record_object?
|
if record_object?
|
||||||
data[:object] = recordable_object(false)
|
data[:object] = recordable_object(false)
|
||||||
end
|
end
|
||||||
|
if record_object_changes?
|
||||||
|
# Rails' implementation returns nothing on destroy :/
|
||||||
|
changes = @record.attributes.map { |attr, value| [attr, [value, nil]] }.to_h
|
||||||
|
data[:object_changes] = prepare_object_changes(changes)
|
||||||
|
end
|
||||||
merge_metadata_into(data)
|
merge_metadata_into(data)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,7 +17,7 @@ module PaperTrail
|
||||||
def initialize(record, in_after_callback, is_touch, force_changes)
|
def initialize(record, in_after_callback, is_touch, force_changes)
|
||||||
super(record, in_after_callback)
|
super(record, in_after_callback)
|
||||||
@is_touch = is_touch
|
@is_touch = is_touch
|
||||||
@changes = force_changes.nil? ? changes : force_changes
|
@force_changes = force_changes
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return attributes of nascent `Version` record.
|
# Return attributes of nascent `Version` record.
|
||||||
|
@ -35,7 +35,8 @@ module PaperTrail
|
||||||
data[:object] = recordable_object(@is_touch)
|
data[:object] = recordable_object(@is_touch)
|
||||||
end
|
end
|
||||||
if record_object_changes?
|
if record_object_changes?
|
||||||
data[:object_changes] = recordable_object_changes(@changes)
|
changes = @force_changes.nil? ? notable_changes : @force_changes
|
||||||
|
data[:object_changes] = prepare_object_changes(changes)
|
||||||
end
|
end
|
||||||
merge_metadata_into(data)
|
merge_metadata_into(data)
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,8 +22,18 @@ RSpec.describe NoObject, versioning: true do
|
||||||
a = n.versions.last.attributes
|
a = n.versions.last.attributes
|
||||||
expect(a).not_to include "object"
|
expect(a).not_to include "object"
|
||||||
expect(a["event"]).to eq "destroy"
|
expect(a["event"]).to eq "destroy"
|
||||||
expect(a["object_changes"]).to be_nil
|
expect(a["object_changes"]).to start_with("---")
|
||||||
expect(a["metadatum"]).to eq(42)
|
expect(a["metadatum"]).to eq(42)
|
||||||
|
|
||||||
|
# New feature: destroy populates object_changes
|
||||||
|
# https://github.com/paper-trail-gem/paper_trail/pull/1123
|
||||||
|
h = YAML.safe_load(a["object_changes"], [::Time])
|
||||||
|
expect(h["id"]).to eq([n.id, nil])
|
||||||
|
expect(h["letter"]).to eq([n.letter, nil])
|
||||||
|
expect(h["created_at"][0]).to be_present
|
||||||
|
expect(h["created_at"][1]).to be_nil
|
||||||
|
expect(h["updated_at"][0]).to be_present
|
||||||
|
expect(h["updated_at"][1]).to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "reify" do
|
describe "reify" do
|
||||||
|
|
|
@ -264,11 +264,18 @@ RSpec.describe(::PaperTrail, versioning: true) do
|
||||||
expect(widget.versions.last.item).to be_nil
|
expect(widget.versions.last.item).to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it "not have changes" do
|
it "has changes" do
|
||||||
widget = Widget.create(name: "Henry")
|
book = Book.create! title: "A"
|
||||||
widget.update_attributes(name: "Harry")
|
changes = YAML.load book.versions.last.attributes["object_changes"]
|
||||||
widget.destroy
|
expect(changes).to eq("id" => [nil, book.id], "title" => [nil, "A"])
|
||||||
expect(widget.versions.last.changeset).to eq({})
|
|
||||||
|
book.update! title: "B"
|
||||||
|
changes = YAML.load book.versions.last.attributes["object_changes"]
|
||||||
|
expect(changes).to eq("title" => %w[A B])
|
||||||
|
|
||||||
|
book.destroy
|
||||||
|
changes = YAML.load book.versions.last.attributes["object_changes"]
|
||||||
|
expect(changes).to eq("id" => [book.id, nil], "title" => ["B", nil])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue