Add the ability to use a custom serializer for storing the object in the database

This commit is contained in:
Bradley Priest 2012-07-04 11:22:52 +08:00
parent f057bee9db
commit 41e255bf51
8 changed files with 118 additions and 10 deletions

View File

@ -727,6 +727,16 @@ Or a block:
end
```
## Using a custom serializer
By default, PaperTrail stores your changes as a YAML dump. You can override this with the serializer config option:
```ruby
>> PaperTrail.serializer = MyCustomSerializer
```
The serializer needs to be a class that responds to a `load` and `dump` method.
## Deleting Old Versions
Over time your `versions` table will grow to an unwieldy size. Because each version is self-contained (see the Diffing section above for more) you can simply delete any records you don't want any more. For example:

View File

@ -5,6 +5,7 @@ require 'paper_trail/config'
require 'paper_trail/controller'
require 'paper_trail/has_paper_trail'
require 'paper_trail/version'
require 'paper_trail/serializers/yaml'
# PaperTrail's module methods can be called in both models and controllers.
module PaperTrail
@ -69,6 +70,9 @@ module PaperTrail
paper_trail_store[:controller_info] = value
end
def self.serializer
PaperTrail.config.serializer
end
private

View File

@ -1,12 +1,13 @@
module PaperTrail
class Config
include Singleton
attr_accessor :enabled, :timestamp_field
attr_accessor :enabled, :timestamp_field, :serializer
def initialize
# Indicates whether PaperTrail is on or off.
@enabled = true
@timestamp_field = :created_at
@serializer = PaperTrail::Serializers::Yaml
end
end
end

View File

@ -162,9 +162,10 @@ module PaperTrail
}
if version_class.column_names.include? 'object_changes'
# The double negative (reject, !include?) preserves the hash structure of self.changes.
data[:object_changes] = self.changes.reject do |key, value|
changes = self.changes.reject do |key, value|
!notably_changed.include?(key)
end.to_yaml
end
data[:object_changes] = PaperTrail.serializer.dump(changes)
end
send(self.class.versions_association_name).build merge_metadata(data)
end
@ -215,7 +216,7 @@ module PaperTrail
end
def object_to_string(object)
object.attributes.except(*self.class.skip).to_yaml
PaperTrail.serializer.dump object.attributes.except(*self.class.skip)
end
def changed_notably?

View File

@ -0,0 +1,23 @@
require 'yaml'
module PaperTrail
module Serializers
class Yaml
def self.load(string)
new.load(string)
end
def self.dump(hash)
new.dump(hash)
end
def load(string)
YAML.load(string)
end
def dump(hash)
YAML.dump(hash)
end
end
end
end

View File

@ -55,7 +55,7 @@ class Version < ActiveRecord::Base
options.reverse_merge! :has_one => false
unless object.nil?
attrs = YAML::load object
attrs = PaperTrail.serializer.load object
# Normally a polymorphic belongs_to relationship allows us
# to get the object we belong to by calling, in this case,
@ -103,7 +103,7 @@ class Version < ActiveRecord::Base
def changeset
if self.class.column_names.include? 'object_changes'
if changes = object_changes
HashWithIndifferentAccess[YAML::load(changes)]
HashWithIndifferentAccess[PaperTrail.serializer.load(changes)]
else
{}
end

View File

@ -49,11 +49,11 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
end
should 'have removed the skipped attributes when saving the previous version' do
assert_equal nil, YAML::load(@old_article.object)['file_upload']
assert_equal nil, PaperTrail.serializer.load(@old_article.object)['file_upload']
end
should 'have kept the non-skipped attributes in the previous version' do
assert_equal 'Some text here.', YAML::load(@old_article.object)['content']
assert_equal 'Some text here.', PaperTrail.serializer.load(@old_article.object)['content']
end
end
end
@ -184,7 +184,7 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
end
should 'have stored changes' do
assert_equal ({'name' => ['Henry', 'Harry']}), YAML::load(@widget.versions.last.object_changes)
assert_equal ({'name' => ['Henry', 'Harry']}), PaperTrail.serializer.load(@widget.versions.last.object_changes)
assert_equal ({'name' => ['Henry', 'Harry']}), @widget.versions.last.changeset
end

View File

@ -0,0 +1,69 @@
require 'test_helper'
class CustomSerializer
require 'json'
def self.dump(object_hash)
JSON.dump object_hash
end
def self.load(string)
JSON.parse string
end
end
class SerializerTest < ActiveSupport::TestCase
context 'YAML Serializer' do
setup do
Fluxor.instance_eval <<-END
has_paper_trail
END
@fluxor = Fluxor.create :name => 'Some text.'
@fluxor.update_attributes :name => 'Some more text.'
end
should 'work with the default yaml serializer' do
# Normal behaviour
assert_equal 2, @fluxor.versions.length
assert_nil @fluxor.versions[0].reify
assert_equal 'Some text.', @fluxor.versions[1].reify.name
# Check values are stored as YAML.
assert_equal "---\nwidget_id: \nname: Some text.\nid: 1\n", @fluxor.versions[1].object
assert_equal ({"widget_id" => nil,"name" =>"Some text.","id" =>1}), YAML.load(@fluxor.versions[1].object)
end
end
context 'Custom Serializer' do
setup do
PaperTrail.config.serializer = CustomSerializer
Fluxor.instance_eval <<-END
has_paper_trail
END
@fluxor = Fluxor.create :name => 'Some text.'
@fluxor.update_attributes :name => 'Some more text.'
end
teardown do
PaperTrail.config.serializer = PaperTrail::Serializers::Yaml
end
should 'work with custom serializer' do
# Normal behaviour
assert_equal 2, @fluxor.versions.length
assert_nil @fluxor.versions[0].reify
assert_equal 'Some text.', @fluxor.versions[1].reify.name
# Check values are stored as JSON.
assert_equal "{\"widget_id\":null,\"name\":\"Some text.\",\"id\":1}", @fluxor.versions[1].object
assert_equal ({"widget_id" => nil,"name" =>"Some text.","id" =>1}), JSON.parse(@fluxor.versions[1].object)
end
end
end