diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cd902d9..402b1d76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,9 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/). - [#1099](https://github.com/paper-trail-gem/paper_trail/issues/1099) - Ability to save ~50% storage space by making the `object` column optional. 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 diff --git a/lib/paper_trail/events/base.rb b/lib/paper_trail/events/base.rb index 2fdbef95..d4692d5a 100644 --- a/lib/paper_trail/events/base.rb +++ b/lib/paper_trail/events/base.rb @@ -119,14 +119,25 @@ module PaperTrail end # @api private - def changes - notable_changes = changes_in_latest_version.delete_if { |k, _v| - !notably_changed.include?(k) - } + def prepare_object_changes(changes) + changes = serialize_object_changes(changes) + changes = recordable_object_changes(changes) + changes + end + + # @api private + def serialize_object_changes(changes) AttributeSerializers::ObjectChangesAttribute. new(@record.class). - serialize(notable_changes) - notable_changes.to_hash + serialize(changes) + changes.to_hash + end + + # @api private + def notable_changes + changes_in_latest_version.delete_if { |k, _v| + !notably_changed.include?(k) + } end # Rails 5.1 changed the API of `ActiveRecord::Dirty`. See diff --git a/lib/paper_trail/events/create.rb b/lib/paper_trail/events/create.rb index e9a637a2..76c014b4 100644 --- a/lib/paper_trail/events/create.rb +++ b/lib/paper_trail/events/create.rb @@ -20,7 +20,8 @@ module PaperTrail data[:created_at] = @record.updated_at end if record_object_changes? && changed_notably? - data[:object_changes] = recordable_object_changes(changes) + changes = notable_changes + data[:object_changes] = prepare_object_changes(changes) end merge_metadata_into(data) end diff --git a/lib/paper_trail/events/destroy.rb b/lib/paper_trail/events/destroy.rb index 3703cff4..a5367bf8 100644 --- a/lib/paper_trail/events/destroy.rb +++ b/lib/paper_trail/events/destroy.rb @@ -21,6 +21,11 @@ module PaperTrail if record_object? data[:object] = recordable_object(false) 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) end end diff --git a/lib/paper_trail/events/update.rb b/lib/paper_trail/events/update.rb index 8207c1e2..c2b59b6b 100644 --- a/lib/paper_trail/events/update.rb +++ b/lib/paper_trail/events/update.rb @@ -17,7 +17,7 @@ module PaperTrail def initialize(record, in_after_callback, is_touch, force_changes) super(record, in_after_callback) @is_touch = is_touch - @changes = force_changes.nil? ? changes : force_changes + @force_changes = force_changes end # Return attributes of nascent `Version` record. @@ -35,7 +35,8 @@ module PaperTrail data[:object] = recordable_object(@is_touch) end 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 merge_metadata_into(data) end diff --git a/spec/models/no_object_spec.rb b/spec/models/no_object_spec.rb index dfd442f3..06feddab 100644 --- a/spec/models/no_object_spec.rb +++ b/spec/models/no_object_spec.rb @@ -22,8 +22,18 @@ RSpec.describe NoObject, versioning: true do a = n.versions.last.attributes expect(a).not_to include "object" 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) + + # 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 describe "reify" do diff --git a/spec/paper_trail/model_spec.rb b/spec/paper_trail/model_spec.rb index 627e190b..41e83bf8 100644 --- a/spec/paper_trail/model_spec.rb +++ b/spec/paper_trail/model_spec.rb @@ -264,11 +264,18 @@ RSpec.describe(::PaperTrail, versioning: true) do expect(widget.versions.last.item).to be_nil end - it "not have changes" do - widget = Widget.create(name: "Henry") - widget.update_attributes(name: "Harry") - widget.destroy - expect(widget.versions.last.changeset).to eq({}) + it "has changes" do + book = Book.create! title: "A" + changes = YAML.load book.versions.last.attributes["object_changes"] + expect(changes).to eq("id" => [nil, book.id], "title" => [nil, "A"]) + + 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