From 0e1b3b483f44b050d180aa78a59c380805fd31dc Mon Sep 17 00:00:00 2001 From: Wyatt Kirby Date: Thu, 13 Jun 2024 16:03:02 -0400 Subject: [PATCH 1/4] Update iterators in auditor to check first whether the audits association is loaded --- lib/audited/auditor.rb | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/audited/auditor.rb b/lib/audited/auditor.rb index e2f1388e..e5e5ec6a 100644 --- a/lib/audited/auditor.rb +++ b/lib/audited/auditor.rb @@ -143,9 +143,9 @@ def with_auditing(&block) # end # def revisions(from_version = 1) - return [] unless audits.from_version(from_version).exists? + return [] unless has_version?(from_version) - all_audits = audits.select([:audited_changes, :version, :action]).to_a + all_audits = audits.pluck(:audited_changes, :version, :action).to_a targeted_audits = all_audits.select { |audit| audit.version >= from_version } previous_attributes = reconstruct_attributes(all_audits - targeted_audits) @@ -156,6 +156,10 @@ def revisions(from_version = 1) end end + def has_version?(version) + audits.loaded? ? audits.any? { |audit| audit.version >= from_version } : audits.from_version(from_version).exists? + end + # Get a specific revision specified by the version number, or +:previous+ # Returns nil for versions greater than revisions count def revision(version) @@ -166,8 +170,8 @@ def revision(version) # Find the oldest revision recorded prior to the date/time provided. def revision_at(date_or_time) - audits = self.audits.up_until(date_or_time) - revision_with Audited.audit_class.reconstruct_attributes(audits) unless audits.empty? + targeted_audits = audits.loaded? ? audits.filter { |audit| audit.created_at <= date_or_time } : audits.up_until(date_or_time) + revision_with Audited.audit_class.reconstruct_attributes(targeted_audits) unless targeted_audits.empty? end # List of attributes that are audited. @@ -323,11 +327,12 @@ def audits_to(version = nil) version = if audit_version audit_version - 1 else - previous = audits.descending.offset(1).first + previous = audits.loaded? ? audits.sort_by { |audit| -audit.version }.second : audits.descending.offset(1).first previous ? previous.version : 1 end end - audits.to_version(version) + + audits.loaded? ? audits.filter { |audit| audit.version <= version } : audits.to_version(version) end def audit_create @@ -386,7 +391,7 @@ def comment_required_state? def combine_audits_if_needed max_audits = audited_options[:max_audits] if max_audits && (extra_count = audits.count - max_audits) > 0 - audits_to_combine = audits.limit(extra_count + 1) + audits_to_combine = audits.loaded? ? audits.take(extra_count + 1) : audits.limit(extra_count + 1) combine_audits(audits_to_combine) end end From 2d42ecdb6f6bc55bf035d298a85a79249d6c78b2 Mon Sep 17 00:00:00 2001 From: Wyatt Kirby Date: Mon, 1 Jul 2024 23:02:56 -0400 Subject: [PATCH 2/4] Update to normalize audit ordering when in loaded branch for auditor interactions --- lib/audited/auditor.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/audited/auditor.rb b/lib/audited/auditor.rb index e5e5ec6a..52549634 100644 --- a/lib/audited/auditor.rb +++ b/lib/audited/auditor.rb @@ -170,7 +170,7 @@ def revision(version) # Find the oldest revision recorded prior to the date/time provided. def revision_at(date_or_time) - targeted_audits = audits.loaded? ? audits.filter { |audit| audit.created_at <= date_or_time } : audits.up_until(date_or_time) + targeted_audits = audits.loaded? ? audits.filter { |audit| audit.created_at <= date_or_time }.sort_by(&:version) : audits.up_until(date_or_time) revision_with Audited.audit_class.reconstruct_attributes(targeted_audits) unless targeted_audits.empty? end @@ -332,7 +332,7 @@ def audits_to(version = nil) end end - audits.loaded? ? audits.filter { |audit| audit.version <= version } : audits.to_version(version) + audits.loaded? ? audits.filter { |audit| audit.version <= version }.sort_by(&:version) : audits.to_version(version) end def audit_create @@ -391,7 +391,7 @@ def comment_required_state? def combine_audits_if_needed max_audits = audited_options[:max_audits] if max_audits && (extra_count = audits.count - max_audits) > 0 - audits_to_combine = audits.loaded? ? audits.take(extra_count + 1) : audits.limit(extra_count + 1) + audits_to_combine = audits.loaded? ? audits.sort_by(&:version).take(extra_count + 1) : audits.limit(extra_count + 1) combine_audits(audits_to_combine) end end From 1b72a971f68494706dbbec2ce4bdf3a5a52362d3 Mon Sep 17 00:00:00 2001 From: Wyatt Kirby Date: Sat, 24 Aug 2024 07:38:16 -0400 Subject: [PATCH 3/4] Fix failing specs --- lib/audited/auditor.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/audited/auditor.rb b/lib/audited/auditor.rb index 52549634..60e33687 100644 --- a/lib/audited/auditor.rb +++ b/lib/audited/auditor.rb @@ -145,7 +145,7 @@ def with_auditing(&block) def revisions(from_version = 1) return [] unless has_version?(from_version) - all_audits = audits.pluck(:audited_changes, :version, :action).to_a + all_audits = audits.loaded? ? audits.to_a : audits.select([:audited_changes, :version, :action]).to_a targeted_audits = all_audits.select { |audit| audit.version >= from_version } previous_attributes = reconstruct_attributes(all_audits - targeted_audits) @@ -157,7 +157,7 @@ def revisions(from_version = 1) end def has_version?(version) - audits.loaded? ? audits.any? { |audit| audit.version >= from_version } : audits.from_version(from_version).exists? + audits.loaded? ? audits.any? { |audit| audit.version >= version } : audits.from_version(version).exists? end # Get a specific revision specified by the version number, or +:previous+ @@ -170,7 +170,7 @@ def revision(version) # Find the oldest revision recorded prior to the date/time provided. def revision_at(date_or_time) - targeted_audits = audits.loaded? ? audits.filter { |audit| audit.created_at <= date_or_time }.sort_by(&:version) : audits.up_until(date_or_time) + targeted_audits = audits.loaded? ? audits.select { |audit| audit.created_at <= date_or_time }.sort_by(&:version) : audits.up_until(date_or_time) revision_with Audited.audit_class.reconstruct_attributes(targeted_audits) unless targeted_audits.empty? end @@ -332,7 +332,7 @@ def audits_to(version = nil) end end - audits.loaded? ? audits.filter { |audit| audit.version <= version }.sort_by(&:version) : audits.to_version(version) + audits.loaded? ? audits.select { |audit| audit.version <= version }.sort_by(&:version) : audits.to_version(version) end def audit_create From 888ddb9c2fd761c6dc84b3a88ed8d71b08d0b206 Mon Sep 17 00:00:00 2001 From: Wyatt Kirby Date: Sat, 24 Aug 2024 10:09:52 -0400 Subject: [PATCH 4/4] Add spec for new has_version? method --- spec/audited/auditor_spec.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spec/audited/auditor_spec.rb b/spec/audited/auditor_spec.rb index a8af7bcb..ddca405d 100644 --- a/spec/audited/auditor_spec.rb +++ b/spec/audited/auditor_spec.rb @@ -917,6 +917,20 @@ def stub_global_max_audits(max_audits) end end + describe "has_version" do + let(:user) { create_versions(2) } + + it "should return true when a version exists" do + expect(user.has_version?(1)).to eq(true) + expect(user.has_version?(2)).to eq(true) + end + + it "should return false when a version does not exist" do + expect(user.has_version?(8)).to eq(false) + expect(user.has_version?(1337)).to eq(false) + end + end + describe "own_and_associated_audits" do it "should return audits for self and associated audits" do owner = Models::ActiveRecord::Owner.create!