升级至Rails 7.0.4后出现undefined method `unloadable'错误求助
Rails 7.0.4 升级后 websocket-rails 启动报错修复指南
问题场景
现有继承自WebsocketRails::BaseController的控制器代码:
class SocketController < WebsocketRails::BaseController before_action :authenticate_user! end
将Rails版本升级至7.0.4后,执行rails s启动服务时触发如下错误:
Failure/Error: class SocketController < WebsocketRails::BaseController before_action :authenticate_user! NoMethodError: undefined method `unloadable' for WebsocketRails::BaseController:Class unloadable controller ^^^^^^^^^^ # ./vendor/bundle/ruby/3.1.0/gems/websocket-rails-0.7.0/lib/websocket_rails/base_controller.rb:45:in `inherited' # ./app/controllers/socket_controller.rb:1:in `<top (required)>' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/kernel.rb:30:in `require' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/kernel.rb:30:in `require' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader/helpers.rb:135:in `const_get' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader/helpers.rb:135:in `cget' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader/eager_load.rb:169:in `block in actual_eager_load_dir' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader/helpers.rb:40:in `block in ls' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader/helpers.rb:25:in `each' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader/helpers.rb:25:in `ls' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader/eager_load.rb:164:in `actual_eager_load_dir' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader/eager_load.rb:17:in `block (2 levels) in eager_load' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader/eager_load.rb:16:in `each' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader/eager_load.rb:16:in `block in eager_load' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader/eager_load.rb:10:in `synchronize' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader/eager_load.rb:10:in `eager_load' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader.rb:296:in `block in eager_load_all' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader.rb:294:in `each' # ./vendor/bundle/ruby/3.1.0/gems/zeitwerk-2.6.6/lib/zeitwerk/loader.rb:294:in `eager_load_all' # ./vendor/bundle/ruby/3.1.0/gems/railties-7.0.4/lib/rails/application/finisher.rb:74:in `block in <module:Finisher>' # ./vendor/bundle/ruby/3.1.0/gems/railties-7.0.4/lib/rails/initializable.rb:32:in `instance_exec' # ./vendor/bundle/ruby/3.1.0/gems/railties-7.0.4/lib/rails/initializable.rb:32:in `run' # ./vendor/bundle/ruby/3.1.0/gems/railties-7.0.4/lib/rails/initializable.rb:61:in `block in run_initializers' # ./vendor/bundle/ruby/3.1.0/gems/railties-7.0.4/lib/rails/initializable.rb:60:in `run_initializers' # ./vendor/bundle/ruby/3.1.0/gems/railties-7.0.4/lib/rails/application.rb:372:in `initialize!' # ./config/environment.rb:5:in `<top (required)>'
问题原因
websocket-rails 0.7.0版本的代码中,WebsocketRails::BaseController的inherited方法调用了Rails旧版本的unloadable方法,但Rails 7.0+默认使用Zeitwerk作为代码加载器,已经移除了unloadable这个方法,导致调用时报错。
修复方案
方案1:给websocket-rails打补丁
在项目的config/initializers目录下新建websocket_rails_patch.rb文件,添加以下代码,手动实现unloadable方法:
module WebsocketRails class BaseController def self.unloadable(_controller = nil) # 空实现,适配Rails7的Zeitwerk加载机制 end end end
保存后重启服务即可解决报错。
方案2:迁移到官方ActionCable
websocket-rails已经多年未更新,后续可能会出现更多兼容性问题。Rails 7默认集成的ActionCable是官方维护的WebSocket解决方案,稳定性和兼容性更好。迁移步骤大致如下:
- 移除Gemfile中的
websocket-rails(Rails7默认已包含ActionCable,无需手动添加) - 将原SocketController的逻辑迁移到ActionCable的Channel中
- 调整前端WebSocket连接代码,适配ActionCable的连接方式
方案3:临时降级Rails版本
如果暂时无法迁移或打补丁,可以将Rails版本降级到websocket-rails支持的版本(比如Rails 6.x),修改Gemfile中的Rails版本后执行bundle install,但这只是临时方案,不推荐长期使用。
内容的提问来源于stack exchange,提问作者suffurt
相关产品推荐
相关产品推荐

