Class: Avo::Resources::ResourceManager

Inherits:
Object
  • Object
show all
Defined in:
lib/avo/resources/resource_manager.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeResourceManager

Returns a new instance of ResourceManager.



64
65
66
# File 'lib/avo/resources/resource_manager.rb', line 64

def initialize
  @resources = self.class.fetch_resources
end

Instance Attribute Details

#resourcesObject Also known as: all

Returns the value of attribute resources.



4
5
6
# File 'lib/avo/resources/resource_manager.rb', line 4

def resources
  @resources
end

Class Method Details

.buildObject



9
10
11
12
13
# File 'lib/avo/resources/resource_manager.rb', line 9

def build
  instance = new
  instance.check_bad_resources
  instance
end

.fetch_resourcesObject

Fetches the resources available to the application. We have two ways of doing that.

  1. Through eager loading.

We automatically eager load the resources directory and fetch the descendants from the scanned files. This is the simple way to get started.

  1. Manually, declared by the user.

We have this option to load the resources because when they are loaded automatically through eager loading, those Resource classes and their methods may trigger loading other classes. And that may disrupt Rails booting process. Ex: AdminResource may use self.model_class = User. That will trigger Ruby to load the User class and itself load other classes in a chain reaction. The scenario that comes up most often is when Rails boots, the routes are being computed which eager loads the resource files. At that boot time some migration might have not been run yet, but Rails tries to access them through model associations, and they are not available.

To enable this feature add a ‘resources` array config in your Avo initializer. config.resources = [

"UserResource",
"FishResource",

]



36
37
38
39
40
41
42
43
44
45
# File 'lib/avo/resources/resource_manager.rb', line 36

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 ones
  Base.descendants - internal_resources
end

.internal_resourcesObject



47
48
49
# File 'lib/avo/resources/resource_manager.rb', line 47

def internal_resources
  [Avo::BaseResource, Avo::Resources::ArrayResource]
end

.load_configured_resourcesObject



55
56
57
58
59
60
61
# File 'lib/avo/resources/resource_manager.rb', line 55

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

.load_resources_namespaceObject



51
52
53
# File 'lib/avo/resources/resource_manager.rb', line 51

def load_resources_namespace
  Rails.autoloaders.main.eager_load_namespace(Avo::Resources)
end

Instance Method Details

#check_bad_resourcesObject



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/avo/resources/resource_manager.rb', line 68

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

#get_available_resources(user = nil) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/avo/resources/resource_manager.rb', line 158

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

#get_model_class_by_name(name) ⇒ Object

Returns the Rails model class by singular snake_cased name

get_model_class_by_name(‘user’) => User



154
155
156
# File 'lib/avo/resources/resource_manager.rb', line 154

def get_model_class_by_name(name)
  name.to_s.camelize.singularize
end

#get_resource(resource) ⇒ Object

Returns the Avo resource by camelized name

get_resource_by_name(‘User’) => instance of Avo::Resources::User



93
94
95
96
97
98
99
# File 'lib/avo/resources/resource_manager.rb', line 93

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

#get_resource_by_controller_name(name) ⇒ Object

Returns the Avo resource by singular snake_cased name

get_resource_by_controller_name(‘delayed_backend_active_record_jobs’) => instance of Avo::Resources::DelayedJob get_resource_by_controller_name(‘users’) => instance of Avo::Resources::User



139
140
141
142
143
144
# File 'lib/avo/resources/resource_manager.rb', line 139

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

#get_resource_by_model_class(klass) ⇒ Object

Returns the Avo resource by singular snake_cased name From all the resources that use the same model_class, it will fetch the first one in alphabetical order

get_resource_by_name(‘User’) => instance of Avo::Resources::User get_resource_by_name(User) => instance of Avo::Resources::User



123
124
125
126
127
128
129
130
131
132
133
# File 'lib/avo/resources/resource_manager.rb', line 123

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

#get_resource_by_name(name) ⇒ Object

Returns the Avo resource by singular snake_cased name

get_resource_by_name(‘user’) => instance of Avo::Resources::User



104
105
106
# File 'lib/avo/resources/resource_manager.rb', line 104

def get_resource_by_name(name)
  get_resource name.singularize.camelize
end

#get_resource_by_plural_name(name) ⇒ Object

Returns the Avo resource by singular snake_cased name

get_resource_by_name(‘z posts’) => instance of Avo::Resources::ZPost



111
112
113
114
115
# File 'lib/avo/resources/resource_manager.rb', line 111

def get_resource_by_plural_name(name)
  resources.find do |resource|
    resource.plural_name == name
  end
end

#guess_resource(name) ⇒ Object

Returns the Avo resource by some name



147
148
149
# File 'lib/avo/resources/resource_manager.rb', line 147

def guess_resource(name)
  get_resource_by_name(name.to_s) || get_resource_by_model_class(name)
end

#resources_for_navigation(user = nil) ⇒ Object



172
173
174
175
176
177
# File 'lib/avo/resources/resource_manager.rb', line 172

def resources_for_navigation(user = nil)
  get_available_resources(user)
    .select do |resource|
      resource.visible_on_sidebar
    end
end

#valid_resourcesObject

Filters out the resources that are missing the model_class



86
87
88
# File 'lib/avo/resources/resource_manager.rb', line 86

def valid_resources
  resources.select { |resource| resource.model_class.present? }.sort_by(&:name)
end