diff --git a/CHANGELOG.md b/CHANGELOG.md index abf70fd4..c8912a4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,9 @@ ### Fixed -- None +- [#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`. ## 5.2.0 (2016-06-27) diff --git a/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb b/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb index 2db28570..7b6ffb60 100644 --- a/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +++ b/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb @@ -34,8 +34,13 @@ module PaperTrail end def serialize(attr, val) - val = defined_enums[attr][val] if defined_enums[attr] - @klass.type_for_attribute(attr).type_cast_for_database(val) + castable_val = val + if defined_enums[attr] + # `attr` is an enum. Find the number that corresponds to `val`. If `val` is + # a number already, there won't be a corresponding entry, just use `val`. + castable_val = defined_enums[attr][val] || val + end + @klass.type_for_attribute(attr).type_cast_for_database(castable_val) end def deserialize(attr, val) @@ -49,6 +54,8 @@ module PaperTrail 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 diff --git a/spec/models/post_with_status_spec.rb b/spec/models/post_with_status_spec.rb index 8c9c9299..35679e96 100644 --- a/spec/models/post_with_status_spec.rb +++ b/spec/models/post_with_status_spec.rb @@ -1,7 +1,7 @@ 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 tests ActiveRecord::Enum, which was added in AR 4.1 +# http://edgeguides.rubyonrails.org/4_1_release_notes.html#active-record-enums describe PostWithStatus, type: :model do if defined?(ActiveRecord::Enum) with_versioning do @@ -22,6 +22,19 @@ describe PostWithStatus, type: :model do expect(subject.changeset["status"]).to eql %w(published archived) end end + + describe "#touch_with_version" do + it "preserves the enum value (and all other attributes)" do + post = described_class.create(status: :draft) + expect(post.versions.count).to eq(1) + expect(post.status).to eq("draft") + Timecop.travel 1.second.since # because MySQL lacks fractional seconds precision + post.paper_trail.touch_with_version + expect(post.versions.count).to eq(2) + expect(post.versions.last[:object]).to include("status: 0") + expect(post.paper_trail.previous_version.status).to eq("draft") + end + end end end end diff --git a/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb b/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb index 60f7ef88..b6ab723c 100644 --- a/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +++ b/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb @@ -173,6 +173,7 @@ class SetUpTestTables < ActiveRecord::Migration create_table :post_with_statuses, force: true do |t| t.integer :status + t.timestamps null: false end create_table :animals, force: true do |t| diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index a35649e7..ec138c53 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -162,7 +162,9 @@ ActiveRecord::Schema.define(version: 20110208155312) do add_index "post_versions", ["item_type", "item_id"], name: "index_post_versions_on_item_type_and_item_id" create_table "post_with_statuses", force: :cascade do |t| - t.integer "status" + t.integer "status" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "posts", force: :cascade do |t|