From 82b73c9b36a5f85c394ee723eb2484f265221a1a Mon Sep 17 00:00:00 2001 From: fatkodima Date: Sat, 15 Jun 2024 21:52:35 +0300 Subject: [PATCH] Do not allow multiple `has_paper_trail` definitions for models --- CHANGELOG.md | 5 ++- lib/paper_trail/has_paper_trail.rb | 2 ++ .../dummy_app/app/models/callback_modifier.rb | 32 ++++++++++++++----- spec/paper_trail/model_config_spec.rb | 10 ++++++ 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5771b1c..c97d772b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,10 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/). ### Breaking Changes -- None +- [#1478](https://github.com/paper-trail-gem/paper_trail/issues/1478) Do not allow + multiple `has_paper_trail` definitions for models. Previously, when `has_paper_trail` + was called on a parent and a child from STI, then possibly multiple `version` records + will be created per event (`create`, `destroy` etc). ### Added diff --git a/lib/paper_trail/has_paper_trail.rb b/lib/paper_trail/has_paper_trail.rb index c509ff0d..bbcf880e 100644 --- a/lib/paper_trail/has_paper_trail.rb +++ b/lib/paper_trail/has_paper_trail.rb @@ -68,6 +68,8 @@ module ClassMethods # # @api public def has_paper_trail(options = {}) + raise Error, "has_paper_trail must be called only once" if self < InstanceMethods + defaults = PaperTrail.config.has_paper_trail_defaults paper_trail.setup(defaults.merge(options)) end diff --git a/spec/dummy_app/app/models/callback_modifier.rb b/spec/dummy_app/app/models/callback_modifier.rb index a287f535..3edf4e85 100644 --- a/spec/dummy_app/app/models/callback_modifier.rb +++ b/spec/dummy_app/app/models/callback_modifier.rb @@ -1,7 +1,11 @@ # frozen_string_literal: true -class CallbackModifier < ApplicationRecord - has_paper_trail on: [] +module CallbackModifier + extend ActiveSupport::Concern + + included do + self.table_name = "callback_modifiers" + end def test_destroy transaction do @@ -17,33 +21,45 @@ def flagged_deleted? end end -class BeforeDestroyModifier < CallbackModifier +class BeforeDestroyModifier < ApplicationRecord + include CallbackModifier + has_paper_trail on: [] paper_trail.on_destroy :before end unless ActiveRecord::Base.belongs_to_required_by_default - class AfterDestroyModifier < CallbackModifier + class AfterDestroyModifier < ApplicationRecord + include CallbackModifier + has_paper_trail on: [] paper_trail.on_destroy :after end end -class NoArgDestroyModifier < CallbackModifier +class NoArgDestroyModifier < ApplicationRecord + include CallbackModifier + has_paper_trail on: [] paper_trail.on_destroy end -class UpdateModifier < CallbackModifier +class UpdateModifier < ApplicationRecord + include CallbackModifier + has_paper_trail on: [] paper_trail.on_update end -class CreateModifier < CallbackModifier +class CreateModifier < ApplicationRecord + include CallbackModifier + has_paper_trail on: [] paper_trail.on_create end -class DefaultModifier < CallbackModifier +class DefaultModifier < ApplicationRecord + include CallbackModifier + has_paper_trail end diff --git a/spec/paper_trail/model_config_spec.rb b/spec/paper_trail/model_config_spec.rb index d5e45fe7..c23d2b78 100644 --- a/spec/paper_trail/model_config_spec.rb +++ b/spec/paper_trail/model_config_spec.rb @@ -5,6 +5,16 @@ module PaperTrail ::RSpec.describe ModelConfig do describe "has_paper_trail" do + it "raises when called multiple times" do + klass = Class.new(ApplicationRecord) do + has_paper_trail + end + + expect do + klass.has_paper_trail + end.to raise_error(Error, "has_paper_trail must be called only once") + end + describe "versions:" do it "name can be passed instead of an options hash", :deprecated do allow(PaperTrail.deprecator).to receive(:warn)