From 52418c077c89d71bbb9cf626343b2a7ba15cb326 Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Wed, 16 Oct 2013 15:28:16 -0400 Subject: [PATCH 1/4] Adding support for PostgreSQL's JSON column type --- CHANGELOG.md | 2 ++ lib/paper_trail/has_paper_trail.rb | 35 +++++++++++++++++++----------- lib/paper_trail/version.rb | 19 +++++++++++++--- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9c8d74e..f15dbdce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## 3.0.0 (Unreleased) + - [#287](https://github.com/airblade/paper_trail/issues/287) - Support for + [PostgreSQL's JSON Type](http://www.postgresql.org/docs/9.2/static/datatype-json.html) for storing `object` and `object_changes`. - [#281](https://github.com/airblade/paper_trail/issues/281) - `Rails::Controller` helper will return `false` for the `paper_trail_enabled_for_controller` method if `PaperTrail.enabled? == false`. - [#280](https://github.com/airblade/paper_trail/pull/280) - Don't track virtual timestamp attributes. diff --git a/lib/paper_trail/has_paper_trail.rb b/lib/paper_trail/has_paper_trail.rb index bc296bdf..ec4312e0 100644 --- a/lib/paper_trail/has_paper_trail.rb +++ b/lib/paper_trail/has_paper_trail.rb @@ -204,7 +204,8 @@ module PaperTrail } if changed_notably? and version_class.column_names.include?('object_changes') - data[:object_changes] = PaperTrail.serializer.dump(changes_for_paper_trail) + data[:object_changes] = version_class.object_changes_col_is_json? ? changes_for_paper_trail : + PaperTrail.serializer.dump(changes_for_paper_trail) end send(self.class.versions_association_name).create! merge_metadata(data) end @@ -212,13 +213,15 @@ module PaperTrail def record_update if paper_trail_switched_on? && changed_notably? + object_attrs = object_attrs_for_paper_trail(item_before_change) data = { :event => paper_trail_event || 'update', - :object => object_to_string(item_before_change), + :object => version_class.object_col_is_json? ? object_attrs : PaperTrail.serializer.dump(object_attrs), :whodunnit => PaperTrail.whodunnit } - if version_class.column_names.include? 'object_changes' - data[:object_changes] = PaperTrail.serializer.dump(changes_for_paper_trail) + if version_class.column_names.include?('object_changes') + data[:object_changes] = version_class.object_changes_col_is_json? ? changes_for_paper_trail : + PaperTrail.serializer.dump(changes_for_paper_trail) end send(self.class.versions_association_name).build merge_metadata(data) end @@ -228,17 +231,22 @@ module PaperTrail self.changes.delete_if do |key, value| !notably_changed.include?(key) end.tap do |changes| - self.class.serialize_attribute_changes(changes) # Use serialized value for attributes when necessary + # don't serialize before values before inserting into columns of type `JSON` on `PostgreSQL` databases + self.class.serialize_attribute_changes(changes) unless version_class.object_changes_col_is_json? end end def record_destroy if paper_trail_switched_on? and not new_record? - version_class.create merge_metadata(:item_id => self.id, - :item_type => self.class.base_class.name, - :event => paper_trail_event || 'destroy', - :object => object_to_string(item_before_change), - :whodunnit => PaperTrail.whodunnit) + object_attrs = object_attrs_for_paper_trail(item_before_change) + data = { + :item_id => self.id, + :item_type => self.class.base_class.name, + :event => paper_trail_event || 'destroy', + :object => version_class.object_col_is_json? ? object_attrs : PaperTrail.serializer.dump(object_attrs), + :whodunnit => PaperTrail.whodunnit + } + version_class.create merge_metadata(data) send(self.class.versions_association_name).send :load_target end end @@ -276,11 +284,12 @@ module PaperTrail end end - def object_to_string(object) + # returns hash of object attributes (with appropriate attributes serialized), ommitting attributes to be skipped + def object_attrs_for_paper_trail(object) _attrs = object.attributes.except(*self.paper_trail_options[:skip]).tap do |attributes| - self.class.serialize_attributes_for_paper_trail attributes + # don't serialize before values before inserting into columns of type `JSON` on `PostgreSQL` databases + self.class.serialize_attributes_for_paper_trail attributes unless version_class.object_changes_col_is_json? end - PaperTrail.serializer.dump(_attrs) end def changed_notably? diff --git a/lib/paper_trail/version.rb b/lib/paper_trail/version.rb index b4f21f5d..7ee92c65 100644 --- a/lib/paper_trail/version.rb +++ b/lib/paper_trail/version.rb @@ -41,6 +41,16 @@ module PaperTrail order("#{PaperTrail.timestamp_field} ASC") } + # Returns whether the `object` column is using the `json` type supported by PostgreSQL + def self.object_col_is_json? + @object_col_is_json ||= columns_hash['object'].type == :json + end + + # Returns whether the `object_changes` column is using the `json` type supported by PostgreSQL + def self.object_changes_col_is_json? + @object_changes_col_is_json ||= columns_hash['object_changes'].type == :json + end + # Restore the item from this version. # # This will automatically restore all :has_one associations as they were "at the time", @@ -58,7 +68,7 @@ module PaperTrail options.reverse_merge! :has_one => false unless object.nil? - attrs = PaperTrail.serializer.load object + attrs = self.class.object_col_is_json? ? object : PaperTrail.serializer.load(object) # Normally a polymorphic belongs_to relationship allows us # to get the object we belong to by calling, in this case, @@ -111,9 +121,12 @@ module PaperTrail def changeset return nil unless self.class.column_names.include? 'object_changes' - @changeset ||= HashWithIndifferentAccess.new(PaperTrail.serializer.load(object_changes)).tap do |changes| + _changes = self.class.object_changes_col_is_json? ? object_changes : PaperTrail.serializer.load(object_changes) + @changeset ||= HashWithIndifferentAccess.new(_changes).tap do |changes| item_type.constantize.unserialize_attribute_changes(changes) - end rescue {} + end + rescue + {} end # Returns who put the item into the state stored in this version. From 5cbc1c8d004245ad939246c99190f050746c457b Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Thu, 17 Oct 2013 16:49:16 -0400 Subject: [PATCH 2/4] Fixing check for whether the object column is of type json in PaperTrail::Model::InstanceMethods.object_attrs_for_paper_trail --- lib/paper_trail/has_paper_trail.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/paper_trail/has_paper_trail.rb b/lib/paper_trail/has_paper_trail.rb index ec4312e0..abf75850 100644 --- a/lib/paper_trail/has_paper_trail.rb +++ b/lib/paper_trail/has_paper_trail.rb @@ -288,7 +288,7 @@ module PaperTrail def object_attrs_for_paper_trail(object) _attrs = object.attributes.except(*self.paper_trail_options[:skip]).tap do |attributes| # don't serialize before values before inserting into columns of type `JSON` on `PostgreSQL` databases - self.class.serialize_attributes_for_paper_trail attributes unless version_class.object_changes_col_is_json? + self.class.serialize_attributes_for_paper_trail attributes unless version_class.object_col_is_json? end end From b32ced84c5cb9adeca55a8068f24a6f5dd30840a Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Thu, 17 Oct 2013 22:05:24 -0400 Subject: [PATCH 3/4] Upcasing the provided YAML and JSON serializers --- CHANGELOG.md | 2 ++ README.md | 8 ++++---- lib/paper_trail/config.rb | 2 +- lib/paper_trail/has_paper_trail.rb | 8 ++++---- lib/paper_trail/serializers/json.rb | 2 +- lib/paper_trail/serializers/yaml.rb | 6 +++--- test/custom_json_serializer.rb | 2 +- test/unit/serializer_test.rb | 12 ++++++------ test/unit/serializers/json_test.rb | 14 +++++++------- test/unit/serializers/mixin_yaml_test.rb | 2 +- test/unit/serializers/yaml_test.rb | 16 ++++++++-------- 11 files changed, 38 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f15dbdce..f45e3ebd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ - [#199](https://github.com/airblade/paper_trail/pull/199) - Rails 4 compatibility. - [#165](https://github.com/airblade/paper_trail/pull/165) - Namespaced the `Version` class under the `PaperTrail` module. - [#119](https://github.com/airblade/paper_trail/issues/119) - Support for [Sinatra](http://www.sinatrarb.com/); decoupled gem from `Rails`. + - Renamed the default serializers from `PaperTrail::Serializers::Yaml` and `PaperTrail::Serializers::Json` to the capitalized forms, + `PaperTrail::Serializers::YAML` and `PaperTrail::Serializers::JSON`. ## 2.7.2 diff --git a/README.md b/README.md index a6f04cda..f2349709 100644 --- a/README.md +++ b/README.md @@ -703,7 +703,7 @@ module PaperTrail end ``` -Why would you do this? In this example, `author_id` is an attribute of `Article` and PaperTrail will store it anyway in serialized (YAML) form in the `object` column of the `version` record. But let's say you wanted to pull out all versions for a particular author; without the metadata you would have to deserialize (reify) each `version` object to see if belonged to the author in question. Clearly this is inefficient. Using the metadata you can find just those versions you want: +Why would you do this? In this example, `author_id` is an attribute of `Article` and PaperTrail will store it anyway in a serialized form in the `object` column of the `version` record. But let's say you wanted to pull out all versions for a particular author; without the metadata you would have to deserialize (reify) each `version` object to see if belonged to the author in question. Clearly this is inefficient. Using the metadata you can find just those versions you want: ```ruby PaperTrail::Version.all(:conditions => ['author_id = ?', author_id]) @@ -849,7 +849,7 @@ end ## Using a custom serializer -By default, PaperTrail stores your changes as a YAML dump. You can override this with the serializer config option: +By default, PaperTrail stores your changes as a `YAML` dump. You can override this with the serializer config option: ```ruby >> PaperTrail.serializer = MyCustomSerializer @@ -857,8 +857,8 @@ By default, PaperTrail stores your changes as a YAML dump. You can override this A valid serializer is a `module` (or `class`) that defines a `load` and `dump` method. These serializers are included in the gem for your convenience: -* [Yaml](https://github.com/airblade/paper_trail/blob/master/lib/paper_trail/serializers/yaml.rb) - Default -* [Json](https://github.com/airblade/paper_trail/blob/master/lib/paper_trail/serializers/json.rb) +* [YAML](https://github.com/airblade/paper_trail/blob/master/lib/paper_trail/serializers/yaml.rb) - Default +* [JSON](https://github.com/airblade/paper_trail/blob/master/lib/paper_trail/serializers/json.rb) ## Limiting the number of versions created per object instance diff --git a/lib/paper_trail/config.rb b/lib/paper_trail/config.rb index 94ffa23c..98114e7c 100644 --- a/lib/paper_trail/config.rb +++ b/lib/paper_trail/config.rb @@ -8,7 +8,7 @@ module PaperTrail def initialize @enabled = true # Indicates whether PaperTrail is on or off. @timestamp_field = :created_at - @serializer = PaperTrail::Serializers::Yaml + @serializer = PaperTrail::Serializers::YAML end end end diff --git a/lib/paper_trail/has_paper_trail.rb b/lib/paper_trail/has_paper_trail.rb index abf75850..2d9bc88b 100644 --- a/lib/paper_trail/has_paper_trail.rb +++ b/lib/paper_trail/has_paper_trail.rb @@ -94,7 +94,7 @@ module PaperTrail def serialize_attributes_for_paper_trail(attributes) serialized_attributes.each do |key, coder| if attributes.key?(key) - coder = PaperTrail::Serializers::Yaml unless coder.respond_to?(:dump) # Fall back to YAML if `coder` has no `dump` method + coder = PaperTrail::Serializers::YAML unless coder.respond_to?(:dump) # Fall back to YAML if `coder` has no `dump` method attributes[key] = coder.dump(attributes[key]) end end @@ -103,7 +103,7 @@ module PaperTrail def unserialize_attributes_for_paper_trail(attributes) serialized_attributes.each do |key, coder| if attributes.key?(key) - coder = PaperTrail::Serializers::Yaml unless coder.respond_to?(:dump) + coder = PaperTrail::Serializers::YAML unless coder.respond_to?(:dump) attributes[key] = coder.load(attributes[key]) end end @@ -113,7 +113,7 @@ module PaperTrail def serialize_attribute_changes(changes) serialized_attributes.each do |key, coder| if changes.key?(key) - coder = PaperTrail::Serializers::Yaml unless coder.respond_to?(:dump) # Fall back to YAML if `coder` has no `dump` method + coder = PaperTrail::Serializers::YAML unless coder.respond_to?(:dump) # Fall back to YAML if `coder` has no `dump` method old_value, new_value = changes[key] changes[key] = [coder.dump(old_value), coder.dump(new_value)] @@ -124,7 +124,7 @@ module PaperTrail def unserialize_attribute_changes(changes) serialized_attributes.each do |key, coder| if changes.key?(key) - coder = PaperTrail::Serializers::Yaml unless coder.respond_to?(:dump) + coder = PaperTrail::Serializers::YAML unless coder.respond_to?(:dump) old_value, new_value = changes[key] changes[key] = [coder.load(old_value), coder.load(new_value)] diff --git a/lib/paper_trail/serializers/json.rb b/lib/paper_trail/serializers/json.rb index c1458d13..a17a52bc 100644 --- a/lib/paper_trail/serializers/json.rb +++ b/lib/paper_trail/serializers/json.rb @@ -2,7 +2,7 @@ require 'active_support/json' module PaperTrail module Serializers - module Json + module JSON extend self # makes all instance methods become module methods as well def load(string) diff --git a/lib/paper_trail/serializers/yaml.rb b/lib/paper_trail/serializers/yaml.rb index d6e72e20..d6e05f4d 100644 --- a/lib/paper_trail/serializers/yaml.rb +++ b/lib/paper_trail/serializers/yaml.rb @@ -2,15 +2,15 @@ require 'yaml' module PaperTrail module Serializers - module Yaml + module YAML extend self # makes all instance methods become module methods as well def load(string) - YAML.load string + ::YAML.load string end def dump(object) - YAML.dump object + ::YAML.dump object end end end diff --git a/test/custom_json_serializer.rb b/test/custom_json_serializer.rb index f705f9b0..8066b448 100644 --- a/test/custom_json_serializer.rb +++ b/test/custom_json_serializer.rb @@ -1,6 +1,6 @@ # This custom serializer excludes nil values module CustomJsonSerializer - extend PaperTrail::Serializers::Json + extend PaperTrail::Serializers::JSON def self.load(string) parsed_value = super(string) diff --git a/test/unit/serializer_test.rb b/test/unit/serializer_test.rb index bef095a7..a9d90102 100644 --- a/test/unit/serializer_test.rb +++ b/test/unit/serializer_test.rb @@ -14,16 +14,16 @@ class SerializerTest < ActiveSupport::TestCase @fluxor.update_attributes :name => 'Some more text.' end - should 'work with the default yaml serializer' do + 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. + # Check values are stored as `YAML`. assert_equal @original_fluxor_attributes, YAML.load(@fluxor.versions[1].object) # This test can't consistently pass in Ruby1.8 because hashes do no preserve order, which means the order of the - # attributes in the YAML can't be ensured. + # attributes in the `YAML` can't be ensured. if RUBY_VERSION.to_f >= 1.9 assert_equal YAML.dump(@original_fluxor_attributes), @fluxor.versions[1].object end @@ -33,7 +33,7 @@ class SerializerTest < ActiveSupport::TestCase context 'JSON Serializer' do setup do PaperTrail.configure do |config| - config.serializer = PaperTrail::Serializers::Json + config.serializer = PaperTrail::Serializers::JSON end Fluxor.instance_eval <<-END @@ -46,7 +46,7 @@ class SerializerTest < ActiveSupport::TestCase end teardown do - PaperTrail.config.serializer = PaperTrail::Serializers::Yaml + PaperTrail.config.serializer = PaperTrail::Serializers::YAML end should 'reify with JSON serializer' do @@ -88,7 +88,7 @@ class SerializerTest < ActiveSupport::TestCase end teardown do - PaperTrail.config.serializer = PaperTrail::Serializers::Yaml + PaperTrail.config.serializer = PaperTrail::Serializers::YAML end should 'reify with custom serializer' do diff --git a/test/unit/serializers/json_test.rb b/test/unit/serializers/json_test.rb index bfc000c3..577d0e3c 100644 --- a/test/unit/serializers/json_test.rb +++ b/test/unit/serializers/json_test.rb @@ -1,6 +1,6 @@ require 'test_helper' -class JsonTest < ActiveSupport::TestCase +class JSONTest < ActiveSupport::TestCase setup do # Setup a hash with random values @@ -17,23 +17,23 @@ class JsonTest < ActiveSupport::TestCase context '`load` class method' do should 'exist' do - assert PaperTrail::Serializers::Json.respond_to?(:load) + assert PaperTrail::Serializers::JSON.respond_to?(:load) end should '`deserialize` JSON to Ruby' do - assert_equal @hash, PaperTrail::Serializers::Json.load(@hash_as_json) - assert_equal @array, PaperTrail::Serializers::Json.load(@array_as_json) + assert_equal @hash, PaperTrail::Serializers::JSON.load(@hash_as_json) + assert_equal @array, PaperTrail::Serializers::JSON.load(@array_as_json) end end context '`dump` class method' do should 'exist' do - assert PaperTrail::Serializers::Json.respond_to?(:dump) + assert PaperTrail::Serializers::JSON.respond_to?(:dump) end should '`serialize` Ruby to JSON' do - assert_equal @hash_as_json, PaperTrail::Serializers::Json.dump(@hash) - assert_equal @array_as_json, PaperTrail::Serializers::Json.dump(@array) + assert_equal @hash_as_json, PaperTrail::Serializers::JSON.dump(@hash) + assert_equal @array_as_json, PaperTrail::Serializers::JSON.dump(@array) end end diff --git a/test/unit/serializers/mixin_yaml_test.rb b/test/unit/serializers/mixin_yaml_test.rb index 273b5dee..6ad2559d 100644 --- a/test/unit/serializers/mixin_yaml_test.rb +++ b/test/unit/serializers/mixin_yaml_test.rb @@ -1,7 +1,7 @@ require 'test_helper' module CustomYamlSerializer - extend PaperTrail::Serializers::Yaml + extend PaperTrail::Serializers::YAML def self.load(string) parsed_value = super(string) diff --git a/test/unit/serializers/yaml_test.rb b/test/unit/serializers/yaml_test.rb index 614203c4..7e9d09a7 100644 --- a/test/unit/serializers/yaml_test.rb +++ b/test/unit/serializers/yaml_test.rb @@ -17,23 +17,23 @@ class YamlTest < ActiveSupport::TestCase context '`load` class method' do should 'exist' do - assert PaperTrail::Serializers::Yaml.respond_to?(:load) + assert PaperTrail::Serializers::YAML.respond_to?(:load) end - should '`deserialize` YAML to Ruby' do - assert_equal @hash, PaperTrail::Serializers::Yaml.load(@hash_as_yaml) - assert_equal @array, PaperTrail::Serializers::Yaml.load(@array_as_yaml) + should 'deserialize `YAML` to Ruby' do + assert_equal @hash, PaperTrail::Serializers::YAML.load(@hash_as_yaml) + assert_equal @array, PaperTrail::Serializers::YAML.load(@array_as_yaml) end end context '`dump` class method' do should 'exist' do - assert PaperTrail::Serializers::Yaml.respond_to?(:dump) + assert PaperTrail::Serializers::YAML.respond_to?(:dump) end - should '`serialize` Ruby to YAML' do - assert_equal @hash_as_yaml, PaperTrail::Serializers::Yaml.dump(@hash) - assert_equal @array_as_yaml, PaperTrail::Serializers::Yaml.dump(@array) + should 'serialize Ruby to `YAML`' do + assert_equal @hash_as_yaml, PaperTrail::Serializers::YAML.dump(@hash) + assert_equal @array_as_yaml, PaperTrail::Serializers::YAML.dump(@array) end end From 43fdce6b6228903db7aa02a5caac58f30d5bdd7a Mon Sep 17 00:00:00 2001 From: Ben Atkins Date: Thu, 17 Oct 2013 22:55:11 -0400 Subject: [PATCH 4/4] Cleanup code dealing with handling of columns of type :json on pg --- lib/paper_trail/has_paper_trail.rb | 46 ++++++++++++++++++------------ 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/lib/paper_trail/has_paper_trail.rb b/lib/paper_trail/has_paper_trail.rb index 2d9bc88b..40f9469e 100644 --- a/lib/paper_trail/has_paper_trail.rb +++ b/lib/paper_trail/has_paper_trail.rb @@ -90,8 +90,15 @@ module PaperTrail self.paper_trail_enabled_for_model = true end + def paper_trail_version_class + @paper_trail_version_class ||= version_class_name.constantize + end + # Used for Version#object attribute def serialize_attributes_for_paper_trail(attributes) + # don't serialize before values before inserting into columns of type `JSON` on `PostgreSQL` databases + return attributes if self.paper_trail_version_class.object_col_is_json? + serialized_attributes.each do |key, coder| if attributes.key?(key) coder = PaperTrail::Serializers::YAML unless coder.respond_to?(:dump) # Fall back to YAML if `coder` has no `dump` method @@ -101,6 +108,9 @@ module PaperTrail end def unserialize_attributes_for_paper_trail(attributes) + # don't serialize before values before inserting into columns of type `JSON` on `PostgreSQL` databases + return attributes if self.paper_trail_version_class.object_col_is_json? + serialized_attributes.each do |key, coder| if attributes.key?(key) coder = PaperTrail::Serializers::YAML unless coder.respond_to?(:dump) @@ -111,6 +121,9 @@ module PaperTrail # Used for Version#object_changes attribute def serialize_attribute_changes(changes) + # don't serialize before values before inserting into columns of type `JSON` on `PostgreSQL` databases + return changes if self.paper_trail_version_class.object_changes_col_is_json? + serialized_attributes.each do |key, coder| if changes.key?(key) coder = PaperTrail::Serializers::YAML unless coder.respond_to?(:dump) # Fall back to YAML if `coder` has no `dump` method @@ -122,6 +135,9 @@ module PaperTrail end def unserialize_attribute_changes(changes) + # don't serialize before values before inserting into columns of type `JSON` on `PostgreSQL` databases + return changes if self.paper_trail_version_class.object_changes_col_is_json? + serialized_attributes.each do |key, coder| if changes.key?(key) coder = PaperTrail::Serializers::YAML unless coder.respond_to?(:dump) @@ -139,12 +155,12 @@ module PaperTrail # Returns true if this instance is the current, live one; # returns false if this instance came from a previous version. def live? - source_version.nil? + @is_live ||= source_version.nil? end # Returns who put the object into its current state. def originator - version_class.with_item_keys(self.class.base_class.name, id).last.try :whodunnit + @originator ||= self.class.paper_trail_version_class.with_item_keys(self.class.base_class.name, id).last.try :whodunnit end # Returns the object (not a Version) as it was at the given timestamp. @@ -188,10 +204,6 @@ module PaperTrail private - def version_class - version_class_name.constantize - end - def source_version send self.class.version_association_name end @@ -203,8 +215,8 @@ module PaperTrail :whodunnit => PaperTrail.whodunnit } - if changed_notably? and version_class.column_names.include?('object_changes') - data[:object_changes] = version_class.object_changes_col_is_json? ? changes_for_paper_trail : + if changed_notably? and self.class.paper_trail_version_class.column_names.include?('object_changes') + data[:object_changes] = self.class.paper_trail_version_class.object_changes_col_is_json? ? changes_for_paper_trail : PaperTrail.serializer.dump(changes_for_paper_trail) end send(self.class.versions_association_name).create! merge_metadata(data) @@ -216,11 +228,11 @@ module PaperTrail object_attrs = object_attrs_for_paper_trail(item_before_change) data = { :event => paper_trail_event || 'update', - :object => version_class.object_col_is_json? ? object_attrs : PaperTrail.serializer.dump(object_attrs), + :object => self.class.paper_trail_version_class.object_col_is_json? ? object_attrs : PaperTrail.serializer.dump(object_attrs), :whodunnit => PaperTrail.whodunnit } - if version_class.column_names.include?('object_changes') - data[:object_changes] = version_class.object_changes_col_is_json? ? changes_for_paper_trail : + if self.class.paper_trail_version_class.column_names.include?('object_changes') + data[:object_changes] = self.class.paper_trail_version_class.object_changes_col_is_json? ? changes_for_paper_trail : PaperTrail.serializer.dump(changes_for_paper_trail) end send(self.class.versions_association_name).build merge_metadata(data) @@ -230,10 +242,7 @@ module PaperTrail def changes_for_paper_trail self.changes.delete_if do |key, value| !notably_changed.include?(key) - end.tap do |changes| - # don't serialize before values before inserting into columns of type `JSON` on `PostgreSQL` databases - self.class.serialize_attribute_changes(changes) unless version_class.object_changes_col_is_json? - end + end.tap { |changes| self.class.serialize_attribute_changes(changes) } end def record_destroy @@ -243,10 +252,10 @@ module PaperTrail :item_id => self.id, :item_type => self.class.base_class.name, :event => paper_trail_event || 'destroy', - :object => version_class.object_col_is_json? ? object_attrs : PaperTrail.serializer.dump(object_attrs), + :object => self.class.paper_trail_version_class.object_col_is_json? ? object_attrs : PaperTrail.serializer.dump(object_attrs), :whodunnit => PaperTrail.whodunnit } - version_class.create merge_metadata(data) + self.class.paper_trail_version_class.create merge_metadata(data) send(self.class.versions_association_name).send :load_target end end @@ -287,8 +296,7 @@ module PaperTrail # returns hash of object attributes (with appropriate attributes serialized), ommitting attributes to be skipped def object_attrs_for_paper_trail(object) _attrs = object.attributes.except(*self.paper_trail_options[:skip]).tap do |attributes| - # don't serialize before values before inserting into columns of type `JSON` on `PostgreSQL` databases - self.class.serialize_attributes_for_paper_trail attributes unless version_class.object_col_is_json? + self.class.serialize_attributes_for_paper_trail(attributes) end end