Вопрос

I have a STI in place for 10 models inheriting from one ActiveRecord::Base model.

class Listing::Numeric < ActiveRecord::Base
end

class Listing::AverageDuration < Listing::Numeric
end

class Listing::TotalViews < Listing::Numeric
end

There are 10 such models those inherit from Listing::Numeric

In rails console, when I try for .descendants or .subclasses it returns an empty array.

Listing::Numeric.descendants
=> []

Listing::Numeric.subclasses
=> []

Ideally this should work.

Any ideas why its not returning the expected subclasses ?

Это было полезно?

Решение 4

This helped me

config.autoload_paths += %W( #{config.root}/app/models/listings )

Taken from here - http://hakunin.com/rails3-load-paths

Другие советы

This will work only if all the inherited classes are referenced in some running code as rails will load the classes when required then only it will be added as descendants

For eg:

Listing::Numeric.descendants.count
=> 0

Listing::AverageDuration
Listing::TotalViews

Listing::Numeric.descendants.count
=> 2

Old Q, but for anyone else like me who get confused with empty lists for subclasses MyClass.subclasses => []

You need to explicitly set the dependency to your MySubclass class.

class MyClass < ApplicationRecord
end
require_dependency 'my_subclass'

$ MyClass.subclasses
=> ['MySubclass']

https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#autoloading-and-sti

Execute Rails.application.eager_load! before calling the .descendants method.

Here is a solution for Rails 7. Originally sourced from RailsGuides, I made modifications to include results even if no data is stored in the table:

module StiPreload
  unless Rails.application.config.eager_load
    extend ActiveSupport::Concern

    included do
      cattr_accessor :preloaded, instance_accessor: false
    end

    class_methods do
      def descendants
        preload_sti unless preloaded
        super
      end

      def preload_sti
        types_from_db = base_class
                      .unscoped
                      .select(inheritance_column)
                      .distinct
                      .pluck(inheritance_column)
                      .compact

        (types_from_db.present? || types_from_file).each do |type|
          type.constantize
        end

        self.preloaded = true
      end

      def types_from_file
        Dir::each_child("#{Rails.root}/app/models").reduce([]) do |acc, filename|
          if filename =~ /^(#{base_class.to_s.split(/(?=[A-Z])/).first.downcase})_(\w+)_datum.rb$/
            acc << "#{$1.capitalize}#{$2.classify}"
          end
          acc
        end
      end
    end
  end
end

class YoursTruly < ApplicationRecord
  include StiPreload
end

YoursTruly.descendants # => [...]
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top