Merge pull request #857 from airblade/read_enums_from_pt4
Fix deserialization of enums written by PT 4
This commit is contained in:
commit
5df7ef3510
|
@ -14,6 +14,8 @@
|
|||
|
||||
### Fixed
|
||||
|
||||
- [#857](https://github.com/airblade/paper_trail/pull/857) -
|
||||
Fix deserialization of enums written by PT 4.
|
||||
- [#798](https://github.com/airblade/paper_trail/issues/798) -
|
||||
Fix a rare bug with serialization of enums in rails 4.2 only when
|
||||
using `touch_with_version`.
|
||||
|
|
|
@ -8,19 +8,41 @@ module PaperTrail
|
|||
# This implementation depends on the `type_for_attribute` method, which was
|
||||
# introduced in rails 4.2. In older versions of rails, we shim this method
|
||||
# with `LegacyActiveRecordShim`.
|
||||
class CastAttributeSerializer
|
||||
def initialize(klass)
|
||||
@klass = klass
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Returns a hash mapping attributes to hashes that map strings to
|
||||
# integers. Example:
|
||||
#
|
||||
# ```
|
||||
# { "status" => { "draft"=>0, "published"=>1, "archived"=>2 } }
|
||||
# ```
|
||||
#
|
||||
# ActiveRecord::Enum was added in AR 4.1
|
||||
# http://edgeguides.rubyonrails.org/4_1_release_notes.html#active-record-enums
|
||||
def defined_enums
|
||||
@defined_enums ||= (@klass.respond_to?(:defined_enums) ? @klass.defined_enums : {})
|
||||
end
|
||||
end
|
||||
|
||||
if ::ActiveRecord::VERSION::MAJOR >= 5
|
||||
# This implementation uses AR 5's `serialize` and `deserialize`.
|
||||
class CastAttributeSerializer
|
||||
def initialize(klass)
|
||||
@klass = klass
|
||||
end
|
||||
|
||||
def serialize(attr, val)
|
||||
@klass.type_for_attribute(attr).serialize(val)
|
||||
end
|
||||
|
||||
def deserialize(attr, val)
|
||||
@klass.type_for_attribute(attr).deserialize(val)
|
||||
if defined_enums[attr] && val.is_a?(::String)
|
||||
# Because PT 4 used to save the string version of enums to `object_changes`
|
||||
val
|
||||
else
|
||||
@klass.type_for_attribute(attr).deserialize(val)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
|
@ -29,10 +51,6 @@ module PaperTrail
|
|||
# `type_cast_for_database` in our shim attribute type classes,
|
||||
# `NoOpAttribute` and `SerializedAttribute`.
|
||||
class CastAttributeSerializer
|
||||
def initialize(klass)
|
||||
@klass = klass
|
||||
end
|
||||
|
||||
def serialize(attr, val)
|
||||
castable_val = val
|
||||
if defined_enums[attr]
|
||||
|
@ -44,21 +62,18 @@ module PaperTrail
|
|||
end
|
||||
|
||||
def deserialize(attr, val)
|
||||
val = @klass.type_for_attribute(attr).type_cast_from_database(val)
|
||||
if defined_enums[attr]
|
||||
defined_enums[attr].key(val)
|
||||
else
|
||||
if defined_enums[attr] && val.is_a?(::String)
|
||||
# Because PT 4 used to save the string version of enums to `object_changes`
|
||||
val
|
||||
else
|
||||
val = @klass.type_for_attribute(attr).type_cast_from_database(val)
|
||||
if defined_enums[attr]
|
||||
defined_enums[attr].key(val)
|
||||
else
|
||||
val
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# ActiveRecord::Enum was added in AR 4.1
|
||||
# http://edgeguides.rubyonrails.org/4_1_release_notes.html#active-record-enums
|
||||
def defined_enums
|
||||
@defined_enums ||= (@klass.respond_to?(:defined_enums) ? @klass.defined_enums : {})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ require "rails_helper"
|
|||
describe PostWithStatus, type: :model do
|
||||
if defined?(ActiveRecord::Enum)
|
||||
with_versioning do
|
||||
let(:post) { PostWithStatus.create!(status: "draft") }
|
||||
let(:post) { described_class.create!(status: "draft") }
|
||||
|
||||
it "should stash the enum value properly in versions" do
|
||||
post.published!
|
||||
|
@ -13,6 +13,16 @@ describe PostWithStatus, type: :model do
|
|||
expect(post.paper_trail.previous_version.published?).to be true
|
||||
end
|
||||
|
||||
it "can read enums in version records written by PT 4" do
|
||||
post = described_class.create(status: "draft")
|
||||
post.published!
|
||||
version = post.versions.last
|
||||
# Simulate behavior PT 4, which used to save the string version of
|
||||
# enums to `object_changes`
|
||||
version.update(object_changes: "---\nid:\n- \n- 1\nstatus:\n- draft\n- published\n")
|
||||
assert_equal %w(draft published), version.changeset["status"]
|
||||
end
|
||||
|
||||
context "storing enum object_changes" do
|
||||
subject { post.versions.last }
|
||||
|
||||
|
|
Loading…
Reference in New Issue