From c5f33191070666af831f0e9d204209481216a178 Mon Sep 17 00:00:00 2001 From: Ray Masiclat Date: Thu, 30 Apr 2026 13:30:57 -0600 Subject: [PATCH 1/2] feat: support Rails 8.1 in PolymorphicArrayValueExtension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rails 8.1 changed `ActiveRecord::PredicateBuilder::PolymorphicArrayValue#initialize` from `(associated_table, values)` to `(reflection, values)`, dropping the `@associated_table` ivar that this gem reads via `@associated_table.send(:reflection)` in `type_to_ids_mapping`. Without an update, every polymorphic-array predicate query (e.g. `Model.where(thing: [a, b])`) raises `NoMethodError: undefined method 'reflection' for nil` on Rails 8.1. The minimal fix: read `@reflection` directly when set (Rails 8.1+), fall back to `@associated_table.send(:reflection)` for older Rails versions. The rest of the method runs unchanged. This also adds Gemfile.rails-8.1-stable to the CI matrix so future regressions are caught upstream rather than in downstream apps. ## Verification The existing spec at `polymorphic_integer_type_spec.rb:135` ("properly finds the object when passing an array of sources") exercises exactly this code path: Link.where(source: [source]) Verified locally: - Rails 8.0: 41/41 passing - Rails 8.1: 41/41 passing - Rails 8.1 *without* this fix: 1 failure (the array-of-sources test) — proves the test catches the regression and the fix resolves it. Downstream apps (clio/accounting, clio/manage, clio/themis, etc.) currently maintain in-app monkey patches for this; bumping to 3.5.0 lets them delete those. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 6 ++++++ CHANGELOG.md | 6 ++++++ gemfiles/Gemfile.rails-8.1-stable | 7 +++++++ .../polymorphic_array_value_extension.rb | 10 +++++++++- lib/polymorphic_integer_type/version.rb | 2 +- 5 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 gemfiles/Gemfile.rails-8.1-stable diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d13f30..4237833 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,7 @@ jobs: - Gemfile.rails-7.0-stable - Gemfile.rails-7.2-stable - Gemfile.rails-8.0-stable + - Gemfile.rails-8.1-stable ruby-version: ['3.0', '3.1', '3.2', '3.3'] exclude: # Rails 7.2 doesn't work with Ruby 3.0 (requires Ruby 3.1+) @@ -27,6 +28,11 @@ jobs: ruby-version: '3.0' - gemfile: Gemfile.rails-8.0-stable ruby-version: '3.1' + # Rails 8.1 requires Ruby 3.2+ + - gemfile: Gemfile.rails-8.1-stable + ruby-version: '3.0' + - gemfile: Gemfile.rails-8.1-stable + ruby-version: '3.1' env: BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }} steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 47b6efe..517b404 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v3.5.0 (2026-04-30) + +### Added + +- Add Rails 8.1 compatibility. Rails 8.1 changed `PredicateBuilder::PolymorphicArrayValue#initialize` from `(associated_table, values)` to `(reflection, values)`, dropping the `@associated_table` ivar. `type_to_ids_mapping` now reads `@reflection` when available and falls back to `@associated_table.send(:reflection)` for older Rails versions. + ## v3.2.1 (2023-12-14) ### Fixed diff --git a/gemfiles/Gemfile.rails-8.1-stable b/gemfiles/Gemfile.rails-8.1-stable new file mode 100644 index 0000000..b6f721a --- /dev/null +++ b/gemfiles/Gemfile.rails-8.1-stable @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gemspec path: ".." + +gem "activerecord", github: "rails/rails", branch: "8-1-stable" diff --git a/lib/polymorphic_integer_type/activerecord_5_0_0/polymorphic_array_value_extension.rb b/lib/polymorphic_integer_type/activerecord_5_0_0/polymorphic_array_value_extension.rb index 1f44ce2..b45df40 100644 --- a/lib/polymorphic_integer_type/activerecord_5_0_0/polymorphic_array_value_extension.rb +++ b/lib/polymorphic_integer_type/activerecord_5_0_0/polymorphic_array_value_extension.rb @@ -10,7 +10,15 @@ module PolymorphicArrayValueExtension # end def type_to_ids_mapping - association = @associated_table.send(:reflection) + # Rails 8.1 changed `PredicateBuilder::PolymorphicArrayValue#initialize` + # from `(associated_table, values)` to `(reflection, values)`, dropping + # the `@associated_table` ivar. Read whichever ivar is available so this + # gem works across Rails 6.1–8.1. + association = if instance_variable_defined?(:@reflection) && @reflection + @reflection + else + @associated_table.send(:reflection) + end name = association.name default_hash = Hash.new { |hsh, key| hsh[key] = [] } diff --git a/lib/polymorphic_integer_type/version.rb b/lib/polymorphic_integer_type/version.rb index c1e9c4d..27b1ad4 100644 --- a/lib/polymorphic_integer_type/version.rb +++ b/lib/polymorphic_integer_type/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module PolymorphicIntegerType - VERSION = '3.4.0' + VERSION = '3.5.0' end From 986cd98c6910e7d8a202dd75942e422538b85c00 Mon Sep 17 00:00:00 2001 From: Ray Masiclat Date: Thu, 30 Apr 2026 13:39:29 -0600 Subject: [PATCH 2/2] test: add multi-type polymorphic-array spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing array-of-sources test only exercises a single-type array (`Link.where(source: [cat])`). The fix's value also covers multi-type arrays (`Link.where(source: [cat, dog])`) — a broader branch of `type_to_ids_mapping` where the result hash spans multiple keys. Locks in coverage on both Rails 8.0 (backwards compat) and 8.1. Suggested by code review. Co-Authored-By: Claude Opus 4.7 (1M context) --- spec/polymorphic_integer_type_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/polymorphic_integer_type_spec.rb b/spec/polymorphic_integer_type_spec.rb index 6e426cf..73a4cdd 100644 --- a/spec/polymorphic_integer_type_spec.rb +++ b/spec/polymorphic_integer_type_spec.rb @@ -136,6 +136,11 @@ expect(Link.where(source: [source])).to eq [link] end + it "properly finds objects when passing an array of mixed-type sources" do + link_for_dog = Link.create(source: dog) + expect(Link.where(source: [cat, dog])).to match_array [link, link_for_dog] + end + it "properly finds the object with a find_by" do expect(Link.find_by(source: source, id: link.id)).to eql link end