Skip excess cloning of JSONized `object_changes` (#1189)

* Skip excess cloning of JSONized `object_changes`

* Suggestions for PR 1189, to be squashed
This commit is contained in:
Sergey Tokarenko 2019-03-13 20:47:23 +03:00 committed by Jared Beck
parent ccf5e1e4d5
commit ca4f532623
3 changed files with 18 additions and 2 deletions

View File

@ -238,9 +238,14 @@ module PaperTrail
# serialization here, using `PaperTrail.serializer`. # serialization here, using `PaperTrail.serializer`.
# #
# @api private # @api private
# @param changes HashWithIndifferentAccess
def recordable_object_changes(changes) def recordable_object_changes(changes)
if PaperTrail.config.object_changes_adapter&.respond_to?(:diff) if PaperTrail.config.object_changes_adapter&.respond_to?(:diff)
changes = PaperTrail.config.object_changes_adapter.diff(changes) # We'd like to avoid the `to_hash` here, because it increases memory
# usage, but that would be a breaking change because
# `object_changes_adapter` expects a plain `Hash`, not a
# `HashWithIndifferentAccess`.
changes = PaperTrail.config.object_changes_adapter.diff(changes.to_hash)
end end
if @record.class.paper_trail.version_class.object_changes_col_is_json? if @record.class.paper_trail.version_class.object_changes_col_is_json?
@ -285,7 +290,10 @@ module PaperTrail
AttributeSerializers::ObjectChangesAttribute. AttributeSerializers::ObjectChangesAttribute.
new(@record.class). new(@record.class).
serialize(changes) serialize(changes)
changes.to_hash
# We'd like to convert this `HashWithIndifferentAccess` to a plain
# `Hash`, but we don't, to save memory.
changes
end end
end end
end end

View File

@ -12,7 +12,12 @@ module PaperTrail
::YAML.load string ::YAML.load string
end end
# @param object (Hash | HashWithIndifferentAccess) - Coming from
# `recordable_object` `object` will be a plain `Hash`. However, due to
# recent [memory optimizations](https://git.io/fjeYv), when coming from
# `recordable_object_changes`, it will be a `HashWithIndifferentAccess`.
def dump(object) def dump(object)
object = object.to_hash if object.is_a?(HashWithIndifferentAccess)
::YAML.dump object ::YAML.dump object
end end

View File

@ -15,6 +15,7 @@ module PaperTrail
float: 4.2 float: 4.2
} }
} }
let(:hash_with_indifferent_access) { HashWithIndifferentAccess.new(hash) }
describe ".load" do describe ".load" do
it "deserializes YAML to Ruby" do it "deserializes YAML to Ruby" do
@ -26,6 +27,8 @@ module PaperTrail
describe ".dump" do describe ".dump" do
it "serializes Ruby to YAML" do it "serializes Ruby to YAML" do
expect(described_class.dump(hash)).to eq(hash.to_yaml) expect(described_class.dump(hash)).to eq(hash.to_yaml)
expect(described_class.dump(hash_with_indifferent_access)).
to eq(hash.stringify_keys.to_yaml)
expect(described_class.dump(array)).to eq(array.to_yaml) expect(described_class.dump(array)).to eq(array.to_yaml)
end end
end end