class Avo::Resources::ResourceManager
def build
def build instance = new instance.check_bad_resources instance end
def check_bad_resources
def check_bad_resources resources.each do |resource| has_model = resource.model_class.present? unless has_model possible_model = resource.to_s.gsub "Avo::Resources::", "" possible_model = possible_model.gsub "Resource", "" Avo.error_manager.add({ url: "https://docs.avohq.io/3.0/resources.html#self_model_class", target: "_blank", message: "#{resource} does not have a valid model assigned. It failed to find the #{possible_model} model. \n\r Please create that model or assign one using self.model_class = YOUR_MODEL" }) end end end
def fetch_resources
"FishResource",
"UserResource",
config.resources = [
To enable this feature add a `resources` array config in your Avo initializer.
and they are not available.
At that boot time some migration might have not been run yet, but Rails tries to access them through model associations,
The scenario that comes up most often is when Rails boots, the routes are being computed which eager loads the resource files.
other classes in a chain reaction.
Ex: AdminResource may use self.model_class = User. That will trigger Ruby to load the User class and itself load
those Resource classes and their methods may trigger loading other classes. And that may disrupt Rails booting process.
We have this option to load the resources because when they are loaded automatically through eager loading,
2. Manually, declared by the user.
This is the simple way to get started.
We automatically eager load the resources directory and fetch the descendants from the scanned files.
1. Through eager loading.
We have two ways of doing that.
Fetches the resources available to the application.
def fetch_resources if Avo.configuration.resources.present? load_configured_resources else load_resources_namespace end # All descendants from Avo::Resources::Base except the internal abstract ones Base.descendants.reject { _1.is_abstract? } end
def get_available_resources(user = nil)
def get_available_resources(user = nil) valid_resources .select do |resource| resource.authorization.class.authorize( user, resource.model_class, Avo.configuration.authorization_methods.stringify_keys["index"], policy_class: resource.authorization_policy, raise_exception: false ) end .sort_by { |r| r.name } end
def get_mapping_for_model(klass)
def get_mapping_for_model(klass) (Avo.configuration.model_resource_mapping || {}).stringify_keys.transform_values(&:to_s)[klass.to_s] end
def get_model_class_by_name(name)
Returns the Rails model class by singular snake_cased name
def get_model_class_by_name(name) name.to_s.camelize.singularize end
def get_resource(resource)
Returns the Avo resource by camelized name
def get_resource(resource) resource = "Avo::Resources::#{resource}" unless resource.to_s.starts_with?("Avo::Resources::") resources.find do |available_resource| resource.to_s == available_resource.to_s end end
def get_resource_by_controller_name(name)
get_resource_by_controller_name('delayed_backend_active_record_jobs') => instance of Avo::Resources::DelayedJob
Returns the Avo resource by singular snake_cased name
def get_resource_by_controller_name(name) valid_resources .find do |resource| resource.model_class.to_s.pluralize.underscore.tr("/", "_") == name.to_s end end
def get_resource_by_model_class(klass)
def get_resource_by_model_class(klass) # Fetch the mappings imposed by the user. # If they are present, use those ones. mapping = get_mapping_for_model klass return get_resource(mapping) if mapping.present? valid_resources .find do |resource| resource.model_class.model_name.name == klass.to_s end end
def get_resource_by_name(name)
Returns the Avo resource by singular snake_cased name
def get_resource_by_name(name) get_resource name.singularize.camelize end
def get_resource_by_plural_name(name)
Returns the Avo resource by singular snake_cased name
def get_resource_by_plural_name(name) resources.find do |resource| resource.plural_name == name end end
def guess_resource(name)
def guess_resource(name) get_resource_by_name(name.to_s) || get_resource_by_model_class(name) end
def initialize
def initialize @resources = self.class.fetch_resources end
def load_configured_resources
def load_configured_resources raise "Resources configuration must be an array" unless Avo.configuration.resources.is_a? Array Avo.configuration.resources.each do |resource| resource.to_s.safe_constantize end end
def load_resources_namespace
def load_resources_namespace Rails.autoloaders.main.eager_load_namespace(Avo::Resources) end
def resources_for_navigation(user = nil)
def resources_for_navigation(user = nil) get_available_resources(user) .select do |resource| resource.visible_on_sidebar end end
def valid_resources
def valid_resources resources.select { |resource| resource.model_class.present? }.sort_by(&:name) end