Class: Avo::App

Inherits:
Object
  • Object
show all
Includes:
Concerns::FetchesThings
Defined in:
lib/avo/app.rb

Class Method Summary collapse

Class Method Details

.bootObject



31
32
33
34
35
36
37
38
39
# File 'lib/avo/app.rb', line 31

def boot
  init_fields

  if Rails.cache.instance_of?(ActiveSupport::Cache::NullStore)
    self.cache_store ||= ActiveSupport::Cache::MemoryStore.new
  else
    self.cache_store = Rails.cache
  end
end

.check_bad_resourcesObject



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/avo/app.rb', line 102

def check_bad_resources
  resources.each do |resource|
    has_model = resource.model_class.present?

    unless has_model
      possible_model = resource.class.to_s.gsub "Resource", ""

      Avo::App.error_messages.push({
        url: "https://docs.avohq.io/2.0/resources.html#custom-model-class",
        target: "_blank",
        message: "#{resource.class.to_s} 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

.debug_report(request = nil) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/avo/app.rb', line 211

def debug_report(request = nil)
  payload = {}

  hq = Avo::Licensing::HQ.new(request)

  payload[:license_id] = Avo::App&.license&.id
  payload[:license_valid] = Avo::App&.license&.valid?
  payload[:license_payload] = Avo::App&.license&.payload
  payload[:license_response] = Avo::App&.license&.response
  payload[:hq_payload] = hq&.payload
  payload[:thread_count] = get_thread_count
  payload[:license_abilities] = Avo::App&.license&.abilities
  payload[:cache_store] = self.cache_store&.class&.to_s
  payload[:avo_metadata] = hq&.
  payload[:app_timezone] = Time.current.zone
  payload[:cache_key] = Avo::Licensing::HQ.cache_key
  payload[:cache_key_contents] = hq&.cached_response

  payload
rescue => e
  e
end

.eager_load(entity) ⇒ Object



20
21
22
23
24
25
26
27
28
29
# File 'lib/avo/app.rb', line 20

def eager_load(entity)
  paths = Avo::ENTITIES.fetch entity

  return unless paths.present?

  pathname = Rails.root.join(*paths)
  if pathname.directory?
    Rails.autoloaders.main.eager_load_dir(pathname.to_s)
  end
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",

]



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/avo/app.rb', line 139

def fetch_resources
  resources = if Avo.configuration.resources.nil?
    BaseResource.descendants
  else
    Avo.configuration.resources
  end

  resources.map do |resource|
    if resource.is_a?(Class)
      resource
    else
      resource.to_s.safe_constantize
    end
  end
end

.get_thread_countObject



234
235
236
237
238
# File 'lib/avo/app.rb', line 234

def get_thread_count
  Thread.list.select {|thread| thread.status == "run"}.count
rescue => e
  e
end

.has_main_menu?Boolean

Returns:

  • (Boolean)


183
184
185
186
187
188
# File 'lib/avo/app.rb', line 183

def has_main_menu?
  return false if Avo::App.license.lacks_with_trial(:menu_editor)
  return false if Avo.configuration.main_menu.nil?

  true
end

.has_profile_menu?Boolean

Returns:

  • (Boolean)


190
191
192
193
194
195
# File 'lib/avo/app.rb', line 190

def has_profile_menu?
  return false if Avo::App.license.lacks_with_trial(:menu_editor)
  return false if Avo.configuration.profile_menu.nil?

  true
end

.init(request:, context:, current_user:, view_context:, params:) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/avo/app.rb', line 49

def init(request:, context:, current_user:, view_context:, params:)
  self.error_messages = []
  self.context = context
  self.current_user = current_user
  self.params = params
  self.request = request
  self.view_context = view_context

  self.license = Licensing::LicenseManager.new(Licensing::HQ.new(request).response).license
  self.translation_enabled = license.has(:localization)

  # Set the current host for ActiveStorage
  begin
    if defined?(ActiveStorage::Current)
      if Rails::VERSION::MAJOR === 6
        ActiveStorage::Current.host = request.base_url
      elsif Rails::VERSION::MAJOR === 7
        ActiveStorage::Current.url_options = request.base_url
      end
    end
  rescue => exception
    Rails.logger.debug "[Avo] Failed to set ActiveStorage::Current.url_options, #{exception.inspect}"
  end

  check_bad_resources
  init_resources
  init_dashboards if license.has_with_trial(:dashboards)
end

.init_dashboardsObject



171
172
173
174
175
176
177
178
179
180
181
# File 'lib/avo/app.rb', line 171

def init_dashboards
  eager_load :dashboards unless Rails.application.config.eager_load

  self.dashboards = Dashboards::BaseDashboard.descendants
    .select do |dashboard|
      dashboard != Dashboards::BaseDashboard
    end
    .uniq do |dashboard|
      dashboard.id
    end
end

.init_fieldsObject

This method will find all fields available in the Avo::Fields namespace and add them to the fields class_variable array so later we can instantiate them on our resources.

If the field has their ‘def_method` set up it will follow that convention, if not it will snake_case the name:

Avo::Fields::TextField -> text Avo::Fields::DateTimeField -> date_time



85
86
87
88
89
90
91
92
93
# File 'lib/avo/app.rb', line 85

def init_fields
  Avo::Fields::BaseField.descendants.each do |class_name|
    next if class_name.to_s == "BaseField"

    if class_name.to_s.end_with? "Field"
      load_field class_name.get_field_name, class_name
    end
  end
end

.init_resourcesObject



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/avo/app.rb', line 155

def init_resources
  self.resources = fetch_resources
    .select do |resource|
      # Remove the BaseResource. We only need the descendants
      resource != BaseResource
    end
    .uniq do |klass|
      # On invalid resource configuration the resource classes get duplicated in `ObjectSpace`
      # We need to de-duplicate them
      klass.name
    end
    .map do |resource|
      resource.new if resource.is_a? Class
    end
end

.load_field(method_name, klass) ⇒ Object



95
96
97
98
99
100
# File 'lib/avo/app.rb', line 95

def load_field(method_name, klass)
  fields.push(
    name: method_name,
    class: klass
  )
end


197
198
199
200
201
202
# File 'lib/avo/app.rb', line 197

def main_menu
  # Return empty menu if the app doesn't have the profile menu configured
  return Avo::Menu::Builder.new.build unless has_main_menu?

  Avo::Menu::Builder.parse_menu(&Avo.configuration.main_menu)
end

.profile_menuObject



204
205
206
207
208
209
# File 'lib/avo/app.rb', line 204

def profile_menu
  # Return empty menu if the app doesn't have the profile menu configured
  return Avo::Menu::Builder.new.build unless has_profile_menu?

  Avo::Menu::Builder.parse_menu(&Avo.configuration.profile_menu)
end

.root_path(paths: [], query: {}, **args) ⇒ Object

Renerate a dynamic root path using the URIService



42
43
44
45
46
47
# File 'lib/avo/app.rb', line 42

def root_path(paths: [], query: {}, **args)
  Avo::Services::URIService.parse(view_context.avo.root_url.to_s)
    .append_paths(paths)
    .append_query(query)
    .to_s
end