I acknowledge your example does indeed answer with that warning. However, I did not get any kind of warning when I trying to replicate the same problem in a rails application using your former example pertaining the active_module gem, either in dev or in production mode:
# models/a.rb
class A < ApplicationRecord
attribute :field, :active_module, possible_modules: [B]
end
#models/b.rb
class B < ApplicationRecord
attribute :field, :active_module, possible_modules: [A]
end
#controllers/test_controller.rb
class TestController < ApplicationController
def index
A.new(field: B)
B.new(field: A)
render plain: 'Hello, Banana'
end
end
─▪ rails s -e production
=> Booting Puma
=> Rails 7.1.5.1 application starting in production
=> Run `bin/rails server --help` for more startup options
W, [2024-12-22T20:36:11.417528 #88583] WARN -- : You are running SQLite in production, this is generally not recommended. You can disable this warning by setting "config.active_record.sqlite3_production_warning=false".
Puma starting in single mode...
* Puma version: 6.5.0 ("Sky's Version")
* Ruby version: ruby 3.2.3 (2024-01-18 revision 52bb2ac0a6) [arm64-darwin23]
* Min threads: 5
* Max threads: 5
* Environment: production
* PID: 88583
* Listening on http://0.0.0.0:3000
Use Ctrl-C to stop
I, [2024-12-22T20:36:13.531121 #88583] INFO -- : [83bb7c72-0865-4333-b4df-4d9db5344483] Started GET "/" for 127.0.0.1 at 2024-12-22 20:36:13 +0000
I, [2024-12-22T20:36:13.534898 #88583] INFO -- : [83bb7c72-0865-4333-b4df-4d9db5344483] Processing by TestController#index as HTML
I, [2024-12-22T20:36:13.556391 #88583] INFO -- : [83bb7c72-0865-4333-b4df-4d9db5344483] Completed 200 OK in 21ms (Views: 0.9ms | ActiveRecord: 2.5ms | Allocations: 8745)
From this little test I am assuming that Rails is somehow properly handling this problem. If somebody can confirm me that this is an issue please let me know.
However, when launching your little example with the a.rb; b.rb, using zeitwerk I do indeed get the error your are talking about
┌─[tmp][]
└─▪ cat a.rb
require_relative 'b'
class A
def say
"say a"
end
end
┌─[tmp][]
└─▪ cat b.rb
require_relative 'a'
class B
def say
"say b"
end
end
┌─[tmp][]
└─▪ cat runner.rb
# runner.rb
require 'zeitwerk'
loader = Zeitwerk::Loader.new
loader.push_dir("./")
loader.setup # ready!
A.new.say
B.new.say
┌─[tmp][]
└─▪ ruby -w runner.rb
/Users/pedrorolo/tmp/b.rb:1: warning: /Users/pedrorolo/tmp/b.rb:1: warning: loading in progress, circular require considered harmful - /Users/pedrorolo/tmp/a.rb
from runner.rb:6:in `<main>'
from /Users/pedrorolo/.rvm/gems/ruby-3.2.3/gems/zeitwerk-2.7.1/lib/zeitwerk/core_ext/kernel.rb:26:in `require'
from <internal:/Users/pedrorolo/.rvm/rubies/ruby-3.2.3/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:136:in `require'
from <internal:/Users/pedrorolo/.rvm/rubies/ruby-3.2.3/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:136:in `require'
from /Users/pedrorolo/tmp/a.rb:1:in `<top (required)>'
from /Users/pedrorolo/tmp/a.rb:1:in `require_relative'
from /Users/pedrorolo/tmp/b.rb:1:in `<top (required)>'
from /Users/pedrorolo/tmp/b.rb:1:in `require_relative'
Anyway, if a AR model needs the referenced module to refer to itself, it can always inject itself or pass itself as argument, thus circunventing that problem:
class ARClass < ActiveRecord::Base
attribute :field, :active_module, possible_modules: [B]
def run_field
field.call(self)
#or
field.new(self).call
end
end