Fix NoMethodError on Rails 8.1 and move the ActiveAdmin 4.0 leg to it - #23
Merged
Merged
Conversation
On Rails 8.1 requiring this gem raises
NoMethodError: undefined method 'delegate_missing_to'
for class Rails::Initializable::Collection
railties 8.1 calls delegate_missing_to in the body of
Rails::Initializable::Collection, but rails/initializable.rb only
requires "tsort" and rails/railtie.rb requires rails/initializable
before any ActiveSupport core ext. This gem requires "rails/railtie"
directly, so it is the first thing to load that file and it trips over
the missing method.
Reproducible with no ActiveAdmin in the picture:
# railties 8.1.4
ruby -e 'require "rails/railtie"' -> NoMethodError
ruby -e 'require "active_support/core_ext/module/delegation"; require "rails/railtie"'
-> OK
# railties 8.0.5.1
ruby -e 'require "rails/railtie"' -> OK
This is a user-facing bug, not a CI detail: the gemspec allows
rails >= 7.2, < 9, so every host app on Rails 8.1 crashes on require.
Fixed by requiring the single core ext railties forgot, which preserves
the existing intent of loading only the minimal Railtie base class
rather than all of Rails -- requiring "rails" or "active_support/rails"
would both pull in far more.
No new spec: all four suites require the gem via spec_helper, so each
one already fails outright on Rails 8.1 without this change.
Now that the gem loads on Rails 8.1 the AA 4.0 leg can test it. Rails 8.0 goes EOL on 2026-11-07 (endoflife.date/rails); 8.1 is supported until 2027-10-10, so this gives the repo a long-lived Rails leg. gemfiles/activeadmin_3.5.gemfile deliberately stays on "~> 8.0.0" so both currently supported Rails series are still covered. The pin stays three-segment: a two-segment "~> 8.1" would mean >= 8.1, < 9.0 and would drift onto 8.2 once that ships, so the leg would stop testing the version it names. Note on merge order: PR #22 adds a comment above this pin naming the Rails 8.1 blocker that this branch fixes. This branch is cut from main, where that comment does not exist yet. If #22 merges first, rebase and delete that now-stale comment.
The pin worked around json 3.0 removing the `quirks_mode` keyword that
ActiveSupport::JSON passed to JSON.parse/JSON.generate. activesupport
8.1 no longer passes it -- `quirks_mode` does not appear anywhere in
activesupport 8.1.4's lib/, while 7.2.3 and 8.0.5.1 both pass it in
lib/active_support/json/{decoding,encoding}.rb. Now that this gemfile
is on Rails 8.1 the workaround is dead weight.
Verified rather than assumed: with the pin removed and no lockfile
(as on CI) bundler resolves json 3.0.2, and all four suites pass on
Ruby 3.4.10 -- 161, 7, 8 and 6 examples, 0 failures, no
"unknown keyword: quirks_mode" anywhere.
gemfiles/activeadmin_3.5.gemfile keeps its pin and its comment: that
leg runs an older activesupport, which still passes the keyword.
Removing the pin there resolves json 3.0.2 and produces 59 failures.
Fivell
force-pushed
the
fix/rails-8-1-railtie-require
branch
from
October 1, 2026 12:28
7cf078f to
c651634
Compare
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
require "activeadmin-oidc"raisesNoMethodErroron Rails 8.1. This fixes itwith a one-line
require, then moves the ActiveAdmin 4.0 CI leg onto Rails 8.1and drops the
json < 3workaround that leg no longer needs.This is a user-facing bug, not a CI detail. The gemspec allows
rails >= 7.2, < 9, so Rails 8.1 is inside the declared support range andevery host app on Rails 8.1 crashes on require today.
Root cause
railties 8.1 added
delegate_missing_to :@collectionto the body ofRails::Initializable::Collection, butrails/initializable.rbonly requires"tsort"— it never requires the ActiveSupport core ext that definesdelegate_missing_to. Andrails/railtie.rbrequiresrails/initializablebefore any
active_support/core_ext.This gem requires
"rails/railtie"directly (deliberately, to registeromniauth-rails_csrf_protection's railtie for host apps without loading all ofRails), so it is the first thing to load that file and it trips over the missing
method.
Reproduction
No ActiveAdmin, no this gem — just railties 8.1.4:
Require the one core ext first and it loads fine:
railties 8.0.5.1 is unaffected — its
initializable.rbdoes not usedelegate_missing_toat all — which is why this only appeared when the 8.1series shipped.
Upstream
The actual defect is in railties: a file that calls
delegate_missing_toshouldrequire
active_support/core_ext/module/delegationitself. This should bereported upstream to rails/rails — the workaround here protects this gem's
users now, but any library that requires
rails/railtiebefore ActiveSupporthits the same wall, so it deserves a fix in railties rather than N copies of
this
requireacross the ecosystem.The fix
lib/activeadmin-oidc.rb, immediately before the existingrequire "rails/railtie":Why the minimal core ext, and not
require "rails"The existing comment block says the gem pulls in the minimal Railtie base class
rather than the full Rails stack, so the require stays safe in contexts where
Rails has not been initialized. Requiring
"rails"or"active_support/rails"would "fix" the NoMethodError by loading far more than this gem needs and would
throw away that property. The single core ext railties forgot keeps the original
intent exactly:
Rails::Railtieis defined,Rails::Applicationis still not loaded. The commentblock above the require has been extended to explain why the core ext has to come
first, so nobody "tidies" it away.
Regression test
None added — the existing suites already are one. All four suites require the
gem through
spec/spec_helper.rb, so on Rails 8.1 without this change every oneof them dies before a single example runs:
Confirmed for
rake spec,spec:engine,spec:isolatedandspec:root. Oncethe ActiveAdmin 4.0 gemfile is on Rails 8.1 (commit 2), CI itself is the guard —
a revert of commit 1 turns all three 8.1 legs red immediately. Adding a separate
clean-process load example would be redundant.
Gemfile change
gemfiles/activeadmin_4.0.gemfilerails "~> 8.0.0"rails "~> 8.1.0"gemfiles/activeadmin_3.5.gemfilerails "~> 8.0.0"Rails 8.0 goes EOL 2026-11-07; 8.1 is supported until 2027-10-10
(endoflife.date/rails), so this gives the repo a
long-lived Rails leg. With the 3.5 leg staying on 8.0, both currently supported
Rails series are covered. The pin stays three-segment:
~> 8.1would mean>= 8.1, < 9.0and would drift onto 8.2 once it ships, so the leg would stoptesting the version it names.
This branch is rebased on top of #22 (now merged), so it also picks up that
PR's Ruby matrix (
['3.3', '3.4', '4.0']) and itsrails "~> 8.0.0"pin on the3.5 leg. #22 had added a comment above the 4.0 gemfile's
railspin naming thisvery blocker; since the blocker is fixed here, that comment is deleted in commit
2 rather than left to rot.
json < 3verdict: dropped from the 4.0 gemfile onlyjson 3.0 removed the
quirks_modekeyword thatActiveSupport::JSONpassed toJSON.parse/JSON.generate. Checked the actual gem sources:quirks_mode?lib/active_support/json/{decoding,encoding}.rblib/Verified rather than assumed. With the pin removed and the lockfile deleted
(CI has no lockfile, which is the whole premise of the pin), bundler resolves
json 3.0.2 against Rails 8.1.4 and all four suites pass with zero
unknown keyword: quirks_modeanywhere.gemfiles/activeadmin_3.5.gemfilekeeps its pin and its comment — that legruns activesupport 8.0, which still passes the keyword. Measured: remove the pin
there and, on Rails 8.0.5.1, bundler resolves json 3.0.2 and the default suite
gives 59 failures / 90
quirks_modementions. The pin is still load-bearingon that leg.
Release
This warrants a patch release. Until it ships,
gem "activeadmin-oidc"isbroken for every host app on Rails 8.1, and the gemspec advertises support for it
(
rails >= 7.2, < 9). I have deliberately not bumpedlib/activeadmin/oidc/version.rb(currently 2.2.1) — the release decision andthe version number are the maintainer's.
Verification
CI=true, all four suites run exactly as the Rakefile invokes them, lockfilesdeleted first so resolution matches CI, explicit
--seed 1:activeadmin_3.5activeadmin_4.0activeadmin_3.5activeadmin_4.0activeadmin_3.5activeadmin_4.0(Re-run after rebasing onto merged #22, so the 3.5 legs here are on Rails 8.0.)
bundle installexited 0 for all six. Ruby 3.3 checked on 3.3.12, never3.3.0 (3.3.0 is the one release with the anonymous-parameter parser bug, which
ruby/setup-rubynever installs forruby-version: '3.3').Seed observations — the pre-existing flake is unchanged by Rails 8.1
spec/spec_helper.rbsetsconfig.order = :randomwith a fresh seed per run, andthe default suite has a pre-existing order dependency on Rails 8 (documented in
#22, present on
maintoday). I re-measured it on Rails 8.1 to see whether themove changes anything.
activeadmin_4.0gemfile, Ruby 3.4.10:main)Identical — same seeds, same failure counts, same two examples:
spec/unit/configuration_spec.rb:203— "#login_submit_path points at theOmniAuth entry point when stub login is off" (builds its expectation from the
global
OmniAuth.config.path_prefix, which Devise overwrites at route-drawtime; under Rails 8 lazy route loading the value depends on spec order)
spec/requests/stub_login_spec.rb:224— "404s when the flag is flipped offafter the route was drawn"
So moving to Rails 8.1 neither fixes nor worsens the flake — roughly 1 seed in
10, on 8.0 and 8.1 alike. I have not touched those specs here; it is unrelated
to this bug and belongs in its own PR.
It already bit this PR's first CI run — and it bites
maintooCI on this branch came back 5 pass / 1 fail on the first attempt: Ruby 3.3 /
activeadmin_3.5.gemfile, seed 18410, 9 failures, allActionController::RoutingErrorinlogout_spec.rb,boot_spec.rbandomniauth_callback_spec.rb— a bigger cluster than the two examples above, butthe same route-draw order dependency underneath. Re-running that one job (new
seed, same commit) turned it green, so the final state is 6/6 pass.
It is not caused by this PR. This PR does not touch the 3.5 gemfile at all,
and the failure reproduces identically on
mainwithout the fix commit:activeadmin_3.5(Rails 8.0)main(2f640aa), no fix commitactiveadmin_3.5(Rails 8.0)Independently:
main's own post-merge CI run for 2f640aa is red, 2 of 6 legs(
Ruby 4.0 / activeadmin_3.5,Ruby 4.0 / activeadmin_4.0), seed 62645, failingon
spec/unit/configuration_spec.rb:203— the same flaky example documented in#22. So the trunk is already intermittently red on its own.
This is the exposure widening that #22 flagged, now visible in practice. Fixing
these specs is the most valuable next piece of work in this repo — it is
currently impossible to tell a real regression from a seed at a glance, which is
exactly the condition in which a real one slips through. Suggested approach for
that PR: stop asserting against the mutable
OmniAuth.config.path_prefixglobal,and give the route-redrawing examples proper setup/teardown so they cannot leak
route state into whatever runs next.
🤖 Generated with Claude Code