Skip to content

Commit

Permalink
Fix issue with enums in AR 4
Browse files Browse the repository at this point in the history
[Fixes #798]
  • Loading branch information
jaredbeck committed May 16, 2016
1 parent 05424b0 commit 52756d0
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Metrics/CyclomaticComplexity:
Max: 13 # Goal: 6

Metrics/ModuleLength:
Max: 299
Max: 307

Metrics/PerceivedComplexity:
Max: 16 # Goal: 7
8 changes: 7 additions & 1 deletion lib/paper_trail/attributes_serialization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ def deserialize(attr, val)
# `NoOpAttribute` and `SerializedAttribute`.
class CastedAttributeSerializer < AbstractSerializer
def serialize(attr, val)
val = defined_enums[attr][val] if defined_enums[attr]
if defined_enums[attr].present? && val.is_a?(::String)
val = defined_enums[attr][val]
end
apply_serialization(:type_cast_for_database, attr, val)
end

Expand All @@ -94,6 +96,10 @@ def deserialize(attr, val)

private

# Returns a Hash that maps column names to hashes, which in turn
# map strings to integers. For example, the PostWithStatus model
# in our test suite has the following:
# {"status"=>{"draft"=>0, "published"=>1, "archived"=>2}}
def defined_enums
@defined_enums ||= (@klass.respond_to?(:defined_enums) ? @klass.defined_enums : {})
end
Expand Down
12 changes: 10 additions & 2 deletions lib/paper_trail/has_paper_trail.rb
Original file line number Diff line number Diff line change
Expand Up @@ -567,8 +567,16 @@ def merge_metadata(data)
end

def attributes_before_change
changed = changed_attributes.select { |k, _v| self.class.column_names.include?(k) }
attributes.merge(changed)
enums = respond_to?(:defined_enums) ? defined_enums : {}
attributes.tap do |prev|
changed = changed_attributes.select { |k, _v|
self.class.column_names.include?(k)
}
changed.each do |attr, before|
before = enums[attr][before] if enums[attr]
prev[attr] = before
end
end
end

# Returns hash of attributes (with appropriate attributes serialized),
Expand Down
42 changes: 33 additions & 9 deletions spec/models/post_with_status_spec.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,49 @@
require "rails_helper"

# This model is in the test suite soley for the purpose of testing ActiveRecord::Enum,
# which is available in ActiveRecord4+ only
# This model is in the test suite solely for the purpose of testing
# ActiveRecord::Enum, which is available in ActiveRecord4+ only
describe PostWithStatus, type: :model do
if defined?(ActiveRecord::Enum)
with_versioning do
let(:post) { PostWithStatus.create!(status: "draft") }

it "should stash the enum value properly in versions" do
it "should save enum value in versions" do
post = PostWithStatus.create!(status: "draft") # enum 0
post.published!
post.archived!
expect(post.previous_version.published?).to be true
expect(post.previous_version.published?).to eq(true)
end

context "storing enum object_changes" do
subject { post.versions.last }
describe "#touch_with_version" do
it "should also save the enum value" do
post = PostWithStatus.create!(status: "draft") # enum 0
expect(post.versions.count).to eq(1)
post.published!
expect(post.versions.count).to eq(2)
expect(post.versions[1].object_deserialized["status"]).to eq(0) # draft
Timecop.travel 1.second.since # because MySQL doesn't do fractional seconds
post.touch_with_version
expect(post.versions.count).to eq(3)
expect(post.versions[2].object_deserialized["status"]).to eq(1) # published
post.archived!
expect(post.versions.count).to eq(4)
expect(post.versions[3].object_deserialized["status"]).to eq(1) # published
expect(post.previous_version.published?).to eq(true)
end
end

describe ".serialize_attributes_for_paper_trail!" do
it "preserves enums" do
expect(
described_class.serialize_attributes_for_paper_trail!("status" => 1)
).to eq("status" => 1)
end
end

context "storing enum object_changes" do
it "should stash the enum value properly in versions object_changes" do
post = PostWithStatus.create!(status: "draft") # enum 0
post.published!
post.archived!
expect(subject.changeset["status"]).to eql %w(published archived)
expect(post.versions.last.changeset["status"]).to eql %w(published archived)
end
end
end
Expand Down

0 comments on commit 52756d0

Please sign in to comment.