Ruby模块执行prepend后无法成为祖先的问题求助
Foreman插件开发中ActiveSupport::Concern模块prepend失效问题
我基于Rails 6.1.7的Foreman(v3.5.1)项目开发插件(使用Foreman Plugin Template),遇到以下问题:
自定义模块ForemanCnames::Concerns::DnsInterfaceExtensions需要prepend到Foreman的DnsInterface模块中,但执行prepend后,该模块并未出现在DnsInterface的祖先列表里。控制台测试如下:
irb(main):001:0> DnsInterface.ancestors => [DnsInterface] irb(main):002:0> DnsInterface.prepend ForemanCnames::Concerns::DnsInterfaceExtensions => DnsInterface irb(main):003:0> DnsInterface.ancestors => [DnsInterface] irb(main):005:0> DnsInterface.prepend Module.new => DnsInterface irb(main):006:0> DnsInterface.ancestors => [#<Module:0x0000558ef346d9d0>, DnsInterface]
我给DnsInterfaceExtensions定义了prepended方法,该方法确实被执行,但新添加的类方法并未生效,模块常量:RECORD_TYPE也未被覆盖,Ruby没有抛出任何错误。
后续排查发现
编辑1:任何继承
ActiveSupport::Concern的空模块都会出现同样现象:irb(main):001:0> (DnsInterface.prepend Module.new { extend ActiveSupport::Concern }).ancestors => [DnsInterface]编辑2:测试发现两个都继承
ActiveSupport::Concern的模块互相prepend时,祖先列表不会更新;但普通模块prepend正常。如果不继承ActiveSupport::Concern,就无法使用prepended回调或class_methods块:irb(main):001:1* module M irb(main):002:1* extend ActiveSupport::Concern irb(main):003:0> end => M irb(main):004:1* module N irb(main):005:1* extend ActiveSupport::Concern irb(main):006:0> end => N irb(main):007:0> (M.prepend N).ancestors => [M]编辑3:猜测问题根源可能是
ActiveSupport::Concern的class_methods会定义:ClassMethods模块,当两个模块都继承ActiveSupport::Concern时,各自的:ClassMethods可能阻碍了祖先关系的建立?
内容的提问来源于stack exchange,提问作者Xavier Mol
相关产品推荐
相关产品推荐

