ruby-on-railssingle-table-inheritanceactivesupport-concerntheforeman

Association not found for subclass of Ruby on Rails STI base class


I'm implementing a plugin to Foreman v3.3.0 that should add some additional parameters to the Subnet model.

# app/models/subnet_extensions.rb
module SubnetExtensions
  extend ActiveSupport::Concern

  included do
    has_one :subnet_bgp_config
  end
end

# lib/engine.rb
class Engine < Rails::Engine
  config.to_prepare
    Subnet.include SubnetExtensions
  end
end

Subnets in Foreman are implemented with single table inheritance (STI) and types Subnet::Ipv6 and Subnet::Ipv4. My issue for the plugin comes up whenever the page for any subnet is rendered:

Association named ‘subnet_bgp_config’ was not found on Subnet::Ipv4; perhaps you misspelled it?

In the Rails console, I can verify that the association simply is not present for the subclasses:

# foreman-rake console (Rails 6.1.7)
irb(main):001:0> Subnet.reflect_on_all_associations.map(&:name).include? :subnet_bgp_config
=> true
irb(main):002:0> Subnet::Ipv4.reflect_on_all_associations.map(&:name).include? :subnet_bgp_config
=> false

I've validated, that this approach works just fine, when the has_one association is written into the Foreman source code. So somehow the method of adding the plugin to Foreman breaks the inheritance.

Even including SubnetExtensions in the console does not work (nor does it raise an error):

irb(main):001:0> Subnet::Ipv4.include ForemanSubnetsWithBGPConfig::SubnetExtensions
=> Subnet::Ipv4(id: integer, network: string, mask: string, priority: integer, name: text, vlanid: integer, created_at: datetime, updated_at: datetime, dhcp_id: integer, tftp_id: integer, gateway: string, dns_primary: string, dns_secondary: string, from: string, to: string, dns_id: integer, boot_mode: string, ipam: string, discovery_id: integer, type: string, description: text, mtu: integer, template_id: integer, httpboot_id: integer, netdb_id: integer, nic_delay: integer, externalipam_id: integer, externalipam_group: text, bmc_id: integer)
irb(main):002:0> Subnet::Ipv4.reflect_on_all_associations.map(&:name).include? :subnet_bgp_config
=> false

Can somebody give hints on what went wrong or pointers what to inspect/try next?


Solution

  • Asking for help on the Foreman developer forum more or less confirms that the issue lies with the load order specific to Foreman. At least the current development branch, which has switched to Rails-7 and Zeitwerk autoloader does not show the same symptoms.