Redmine插件报check_if_login_required回调未定义问题排查
故障根因
该报错与子类隐藏祖父类方法无关,核心是Rails 5.2的skip_before_action校验逻辑变更 + 插件控制器补丁加载时序错误:
- Rails 5.2 中
skip_before_action会在类加载阶段立即校验要跳过的回调是否已在当前类/祖先链上注册,不再像Rails 4一样延迟到请求处理阶段做回调查找。 - 故障环境实际运行时的类加载顺序不符合预期:
- Redmine核心启动时优先加载自身的
ApplicationController,紧接着加载核心AccountController,执行skip_before_action :check_if_login_required, :check_password_change语句 - 此时插件目录下的
application_controller.rb尚未被加载,check_if_login_required回调还未注册到ApplicationController上,直接触发has not been defined异常 - 等核心控制器加载完成后,插件的ApplicationController补丁才被自动加载,此时回调注册已经晚于skip操作的执行时机。
- Redmine核心启动时优先加载自身的
- 生产环境运行正常的原因是Rails生产环境默认开启
config.eager_load = true,插件代码会在核心控制器加载前完成预加载,check_if_login_required回调注册早于AccountController的skip操作,因此不会触发报错。复制Gemfile.lock无法解决问题,因为故障和Gem版本依赖无关,是代码加载顺序差异导致。
修复方案
修改插件根目录下的init.rb文件,在Redmine::Plugin.register代码块外添加显式预加载语句,强制插件的ApplicationController补丁在核心控制器加载前完成加载:
require File.expand_path('../app/controllers/application_controller', __FILE__)
修改完成后重启Redmine服务即可恢复正常。
内容的提问来源于stack exchange,提问作者Gary Aitken
相关产品推荐
相关产品推荐

