module AutoAdmin class Node class << self def nodes @nodes ||= begin Rails.application.eager_load! ActiveRecord::Base.descendants.each_with_object({}) do |klass, hash| next if klass.abstract_class? || klass.name.split('::').first == 'ActiveRecord' hash[klass.name] = AutoAdmin::Node.new(klass) end end end def preload_associations! # rubocop:disable Metrics/MethodLength, Metrics/AbcSize return true if @preloading @preloading = true @preload_associations ||= begin nodes.values.each do |node| node.klass.reflect_on_all_associations(:has_many).each do |association| node.has_many association unless association.options[:through] end node.klass.reflect_on_all_associations(:has_one).each do |association| node.has_one association end node.klass.reflect_on_all_associations(:belongs_to).each do |association| node.belongs_to association unless association.polymorphic? end end true end end def root_nodes nodes.values.select { |n| n.belongs_to.none? }.sort_by { |n| -n.weight } end end attr_accessor :klass delegate :name, :to_s, to: :klass def initialize(klass) self.klass = klass end def define_routes!(ctx) ctx.resources resource_name, controller: 'resources', defaults: { node: klass.name }, only: %i(index show), shallow: true do has_many.map(&:node).each do |child_node| child_node.define_routes!(ctx) end end end def resource_name klass.name.demodulize.underscore.pluralize end def polymorphic_path [resource_name] end def attributes klass.column_names - primary_keys - belongs_to.map(&:node).map { |hm| hm.to_s.foreign_key } end def primary_keys klass.respond_to?(:primary_keys) ? klass.primary_keys : [klass.primary_key] end def weight @weight ||= has_many.map(&:node).sum(&:weight) + 1 end def has_many(association = nil) # rubocop:disable Metrics/AbcSize @has_many ||= Set.new if association node = self.class.nodes[association.klass.name] node.belongs_to << Association.new(self, association.inverse_of) if association.inverse_of @has_many << Association.new(node, association.name) else self.class.preload_associations! end @has_many end def has_one(association = nil) # rubocop:disable Metrics/AbcSize @has_one ||= Set.new if association node = self.class.nodes[association.klass.name] node.belongs_to << Association.new(self, association.inverse_of) if association.inverse_of @has_one << Association.new(node, association.name) else self.class.preload_associations! end @has_one end def belongs_to(association = nil) @belongs_to ||= Set.new if association node = self.class.nodes[association.klass.name] @belongs_to << Association.new(node, association.name) else self.class.preload_associations! end @belongs_to end end end