From 2c88d6c42071945f7bead73362fc9910fe470d01 Mon Sep 17 00:00:00 2001 From: Grant Hutchins Date: Mon, 10 Aug 2026 12:27:47 -0500 Subject: [PATCH] Drop support for Active Record 7.2 Active Record 7.2 reached end of life on 2026-08-09, so require Active Record 8.0 or later and stop exercising 7.2 release and stable branches in CI. Remove obsolete compatibility paths along with it: an Active Record 4-era table existence fallback, dependency-reference cache cleanup that modern Active Support no longer defines, and redundant Active Support descendants cleanup. The gem still filters destroyed model classes itself because Active Record 8 exposes them when descendant clearing is disabled, and follows Rails main by prepending that filter so later class-method extensions cannot bypass it. --- .github/workflows/ci.yml | 7 ------- CHANGELOG.md | 2 ++ lib/with_model/descendants_tracker.rb | 14 +++----------- lib/with_model/model.rb | 13 ------------- lib/with_model/table.rb | 8 +------- spec/descendants_tracking_spec.rb | 22 ++++++++++++++++++++-- spec/table_false_spec.rb | 4 ---- with_model.gemspec | 2 +- 8 files changed, 27 insertions(+), 45 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b3fa3e..5ce0e47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,8 +29,6 @@ jobs: matrix: ruby-version: ["3.3", "3.4", "4.0"] active-record: - - label: AR 7.2 - env: ACTIVE_RECORD_VERSION=~> 7.2.0 - label: AR 8.0 env: ACTIVE_RECORD_VERSION=~> 8.0.0 - label: AR 8.1 @@ -52,11 +50,6 @@ jobs: label: AR 8-0-stable env: ACTIVE_RECORD_BRANCH=8-0-stable allow-failure: true - - ruby-version: "4.0" - active-record: - label: AR 7-2-stable - env: ACTIVE_RECORD_BRANCH=7-2-stable - allow-failure: true # A canary for the next Ruby, which cannot fail the build. - ruby-version: ruby-head active-record: diff --git a/CHANGELOG.md b/CHANGELOG.md index d06aa42..7a59c67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ### Unreleased +- Require Active Record 8.0 or later. + ### 2.3.1 - Honor Active Record destruction callbacks and dependent associations when diff --git a/lib/with_model/descendants_tracker.rb b/lib/with_model/descendants_tracker.rb index a845508..c6b19ab 100644 --- a/lib/with_model/descendants_tracker.rb +++ b/lib/with_model/descendants_tracker.rb @@ -74,14 +74,6 @@ def descendants end end -class ActiveRecord::Base - extend WithModel::DescendantsTracker::DestroyedClassesFiltering -end - -module ActiveSupport - module DescendantsTracker - class << self - attr_reader :clear_disabled - end - end -end +ActiveRecord::Base.singleton_class.prepend( + WithModel::DescendantsTracker::DestroyedClassesFiltering +) diff --git a/lib/with_model/model.rb b/lib/with_model/model.rb index 9e68471..0f5e343 100644 --- a/lib/with_model/model.rb +++ b/lib/with_model/model.rb @@ -74,8 +74,6 @@ def destroy # can only do so while the class still has its name. table.teardown(@model) stubber.unstub_const - cleanup_descendants_tracking - reset_dependencies_cache WithModel::DescendantsTracker.clear([@model]) @model = nil end @@ -132,17 +130,6 @@ def setup_model @model.reset_column_information end - def cleanup_descendants_tracking - ActiveSupport::DescendantsTracker.clear([@model]) \ - unless ActiveSupport::DescendantsTracker.clear_disabled - end - - def reset_dependencies_cache - return unless defined?(ActiveSupport::Dependencies::Reference) - - ActiveSupport::Dependencies::Reference.clear! - end - def stubber @stubber ||= ConstantStubber.new const_name end diff --git a/lib/with_model/table.rb b/lib/with_model/table.rb index 457998a..e869172 100644 --- a/lib/with_model/table.rb +++ b/lib/with_model/table.rb @@ -45,12 +45,6 @@ def destroy attr_reader :connection - def exists? - if connection.respond_to?(:data_source_exists?) - connection.data_source_exists?(@name) - else - connection.table_exists?(@name) - end - end + def exists? = connection.data_source_exists?(@name) end end diff --git a/spec/descendants_tracking_spec.rb b/spec/descendants_tracking_spec.rb index 0ffdef8..d5eb00c 100644 --- a/spec/descendants_tracking_spec.rb +++ b/spec/descendants_tracking_spec.rb @@ -30,7 +30,6 @@ def blog_post_classes context "with ActiveSupport::DescendantsTracker (cache_classes: true)" do before do - expect(ActiveSupport::DescendantsTracker.clear_disabled).to be_falsey expect { ActiveSupport::DescendantsTracker.clear([]) }.not_to raise_exception end @@ -40,10 +39,29 @@ def blog_post_classes context "without ActiveSupport::DescendantsTracker (cache_classes: false)" do before do ActiveSupport::DescendantsTracker.disable_clear! - expect(ActiveSupport::DescendantsTracker.clear_disabled).to be_truthy expect { ActiveSupport::DescendantsTracker.clear([]) }.to raise_exception(RuntimeError) end include_examples "clearing descendants between test runs" end + + it "keeps filtering ahead of later class method extensions" do + raw_subclasses = Class.instance_method(:subclasses).super_method + raw_descendants = Class.instance_method(:descendants).super_method + override = Module.new do + define_method(:subclasses) { raw_subclasses.bind_call(self) } + define_method(:descendants) { raw_descendants.bind_call(self) } + end + destroyed_model = stub_const("DestroyedModel", Class.new(ActiveRecord::Base)) + WithModel::DescendantsTracker.clear([destroyed_model]) + + ActiveRecord::Base.extend override + + expect(ActiveRecord::Base.descendants).not_to include(destroyed_model) + ensure + override&.module_eval do + remove_method :subclasses + remove_method :descendants + end + end end diff --git a/spec/table_false_spec.rb b/spec/table_false_spec.rb index 66a554c..eefb8f5 100644 --- a/spec/table_false_spec.rb +++ b/spec/table_false_spec.rb @@ -21,10 +21,6 @@ def stub_active_record_class(name, superclass: ActiveRecord::Base) classes = @stubbed_active_record_classes next unless classes - ActiveSupport::DescendantsTracker.clear(classes) \ - unless ActiveSupport::DescendantsTracker.clear_disabled - ActiveSupport::Dependencies::Reference.clear! \ - if defined?(ActiveSupport::Dependencies::Reference) WithModel::DescendantsTracker.clear(classes) end diff --git a/with_model.gemspec b/with_model.gemspec index 19a4fcc..8ccab57 100644 --- a/with_model.gemspec +++ b/with_model.gemspec @@ -20,5 +20,5 @@ Gem::Specification.new do |spec| spec.required_ruby_version = ">= 3.3" - spec.add_dependency "activerecord", ">= 7.2" + spec.add_dependency "activerecord", ">= 8.0" end