Changed #changeset so that it automatically unserializes any serialized attributes.

Now version.changeset returns the same thing that record.changes returned before the save.
This commit is contained in:
Tyler Rick 2012-11-05 12:07:50 -08:00
parent 8b8579a81a
commit ae2350b147
3 changed files with 39 additions and 11 deletions

View File

@ -189,10 +189,10 @@ module PaperTrail
# Use serialized value for attributes that are serialized
changes_hash.each do |key, (old_value, new_value)|
if serialized_attributes.include?(key)
# serializer.dump(new_value) is the same as @attributes[key].serialized_value
serializer = @attributes[key].coder
changes_hash[key] = [serializer.dump(old_value),
serializer.dump(new_value)]
# coder.dump(new_value) is the same as @attributes[key].serialized_value
coder = @attributes[key].coder
changes_hash[key] = [coder.dump(old_value),
coder.dump(new_value)]
end
end
end

View File

@ -103,7 +103,15 @@ class Version < ActiveRecord::Base
def changeset
if self.class.column_names.include? 'object_changes'
if changes = object_changes
HashWithIndifferentAccess[YAML::load(changes)]
HashWithIndifferentAccess[YAML::load(changes)].tap do |changes|
item_type.constantize.serialized_attributes.each do |key, coder|
if changes.key?(key)
old_value, new_value = changes[key]
changes[key] = [coder.load(old_value),
coder.load(new_value)]
end
end
end
else
{}
end

View File

@ -914,17 +914,37 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
end
context 'when that attribute is updated' do
setup { @person.update_attributes({ :time_zone => 'Pacific Time (US & Canada)' }) }
should 'have used the value returned by the serializer' do
assert_equal ['UTC', 'Pacific Time (US & Canada)'], @person.versions.last.changeset[:time_zone]
assert_equal @person.instance_variable_get(:@attributes)['time_zone'].serialized_value, @person.versions.last.changeset[:time_zone].last
setup do
@person.assign_attributes({ :time_zone => 'Pacific Time (US & Canada)' })
@changes_before_save = @person.changes.dup
@person.save!
end
should 'not have stored the default, ridiculously long (to_yaml) serialization of the time_zone object' do
# Tests for serialization:
should 'object_changes have stored the value returned by the attribute serializer' do
as_stored = HashWithIndifferentAccess[YAML::load(@person.versions.last.object_changes)]
assert_equal ['UTC', 'Pacific Time (US & Canada)'], as_stored[:time_zone]
assert_equal @person.instance_variable_get(:@attributes)['time_zone'].serialized_value, as_stored[:time_zone].last
end
should 'not have stored the default, ridiculously long (to_yaml) serialization of the TimeZone object' do
# Before the serialized attributes fix, the object_changes that was stored was ridiculously long (58723)
assert @person.versions.last.object_changes.length < 105, "object_changes length was #{@person.versions.last.object_changes.length}"
end
# Tests for unserialization:
should '#changeset should convert the attribute value back to its original, unserialized value' do
as_stored = HashWithIndifferentAccess[YAML::load(@person.versions.last.object_changes)]
assert_equal ['UTC', 'Pacific Time (US & Canada)'], as_stored[:time_zone]
assert_equal @person.instance_variable_get(:@attributes)['time_zone'].serialized_value, as_stored[:time_zone].last
end
should "record.changes (before save) returns the original, unserialized values" do
assert_equal [ActiveSupport::TimeZone, ActiveSupport::TimeZone], @changes_before_save[:time_zone].map(&:class)
end
should 'version.changeset should be the same as record.changes was before the save' do
assert_equal @changes_before_save, @person.versions.last.changeset
assert_equal [ActiveSupport::TimeZone, ActiveSupport::TimeZone], @person.versions.last.changeset[:time_zone].map(&:class)
end
end
end