class Avo::BaseResource
def action(action_class, arguments: {})
def action(action_class, arguments: {}) self.actions_loader ||= Avo::Loaders::Loader.new action = { class: action_class, arguments: arguments } self.actions_loader.use action end
def attached_file_fields
def attached_file_fields get_field_definitions.select do |field| [Avo::Fields::FileField, Avo::Fields::FilesField].include? field.class end end
def authorization
def authorization Avo::Services::AuthorizationService.new Avo::App.current_user, model_class, policy_class: authorization_policy end
def authorization(user: nil)
def authorization(user: nil) current_user = user || Avo::App.current_user Avo::Services::AuthorizationService.new(current_user, model || model_class, policy_class: authorization_policy) end
def available_view_types
def available_view_types view_types = [:table] view_types << :grid if get_grid_fields.present? view_types end
def avatar
def avatar return avatar_field.to_image if avatar_field.respond_to? :to_image return avatar_field.value.variant(resize_to_limit: [480, 480]) if avatar_field.type == "file" avatar_field.value rescue nil end
def avatar_field
def avatar_field get_field_definitions.find do |field| field.as_avatar.present? end rescue nil end
def avatar_type
def avatar_type avatar_field.as_avatar rescue nil end
def cache_hash(parent_model)
def cache_hash(parent_model) if parent_model.present? [model, file_hash, parent_model] else [model, file_hash] end end
def class_name_without_resource
def class_name_without_resource self.class.name.demodulize.delete_suffix("Resource") end
def default_panel_name
def default_panel_name return @params[:related_name].capitalize if @params.present? && @params[:related_name].present? case @view when :show model_title when :edit model_title when :new t("avo.create_new_item", item: name.downcase).upcase_first end end
def description
def description description_field&.value end
def description_field
def description_field get_field_definitions.find do |field| field.as_description.present? end rescue nil end
def file_hash
def file_hash content_to_be_hashed = "" # resource file hash resource_path = Rails.root.join("app", "avo", "resources", "#{self.class.name.underscore}.rb").to_s if File.file? resource_path content_to_be_hashed += File.read(resource_path) end # policy file hash policy_path = Rails.root.join("app", "policies", "#{self.class.name.underscore.gsub("_resource", "")}_policy.rb").to_s if File.file? policy_path content_to_be_hashed += File.read(policy_path) end Digest::MD5.hexdigest(content_to_be_hashed) end
def fill_model(model, params, extra_params: [])
def fill_model(model, params, extra_params: []) # Map the received params to their actual fields fields_by_database_id = get_field_definitions .reject do |field| field.computed end .map do |field| [field.database_id.to_s, field] end .to_h # Write the field values params.each do |key, value| field = fields_by_database_id[key] next unless field.present? model = field.fill_field model, key, value, params end # Write the user configured extra params to the model if extra_params.present? # Let Rails fill in the rest of the params model.assign_attributes params.permit(extra_params) end model end
def filter(filter_class, arguments: {})
def filter(filter_class, arguments: {}) self.filters_loader ||= Avo::Loaders::Loader.new filter = { class: filter_class , arguments: arguments } self.filters_loader.use filter end
def find_record(id, query: nil, params: nil)
def find_record(id, query: nil, params: nil) query ||= self.class.find_scope self.class.find_record_method.call(model_class: query, id: id, params: params) end
def find_scope
def find_scope final_scope = resolve_find_scope.present? ? resolve_find_scope.call(model_class: model_class) : model_class authorization.apply_policy final_scope end
def form_scope
def form_scope model_class.base_class.to_s.underscore.downcase end
def get_action_arguments(action_class)
def get_action_arguments(action_class) action = get_actions.find { |action| action[:class].to_s == action_class.to_s } action[:arguments] end
def get_actions
def get_actions return [] if self.class.actions_loader.blank? self.class.actions_loader.bag end
def get_available_models
def get_available_models ApplicationRecord.descendants end
def get_filter_arguments(filter_class)
def get_filter_arguments(filter_class) filter = get_filters.find { |filter| filter[:class] == filter_class.constantize } filter[:arguments] end
def get_filters
def get_filters return [] if self.class.filters_loader.blank? self.class.filters_loader.bag end
def get_grid_fields
def get_grid_fields return if self.class.grid_loader.blank? self.class.grid_loader.hydrate(model: @model, view: @view, resource: self) end
def get_record_associations(record)
def get_record_associations(record) record._reflections end
def grid(&block)
def grid(&block) grid_collector = GridCollector.new grid_collector.instance_eval(&block) self.grid_loader = grid_collector end
def has_model_id?
def has_model_id? model.present? && model.id.present? end
def hydrate(model: nil, view: nil, user: nil, params: nil)
def hydrate(model: nil, view: nil, user: nil, params: nil) @view = view if view.present? @user = user if user.present? @params = params if params.present? if model.present? @model = model hydrate_model_with_default_values if @view == :new end self end
def hydrate_model_with_default_values
def hydrate_model_with_default_values default_values = get_fields .select do |field| !field.computed end .map do |field| id = field.id value = field.value if field.type == "belongs_to" id = field.foreign_key.to_sym reflection = @model._reflections[@params[:via_relation]] if field.polymorphic_as.present? && field.types.map(&:to_s).include?(@params[:via_relation_class]) # set the value to the actual record value = @params[:via_relation_class].safe_constantize.find(@params[:via_resource_id]) elsif reflection.present? && reflection.foreign_key.present? && field.id.to_s == @params[:via_relation].to_s resource = Avo::App.get_resource_by_model_name params[:via_relation_class] model = resource.find_record @params[:via_resource_id], params: params id_param = reflection.options[:primary_key] || :id value = model.send(id_param) end end [id, value] end .to_h .select do |id, value| value.present? end default_values.each do |id, value| if @model.send(id).nil? @model.send("#{id}=", value) end end end
def initialize
def initialize unless self.class.model_class.present? if model_class.present? && model_class.respond_to?(:base_class) self.class.model_class = model_class.base_class end end end
def label
def label label_field&.value || model_title end
def label_field
def label_field get_field_definitions.find do |field| field.as_label.present? end rescue nil end
def model_class
def model_class # get the model class off of the static property return self.class.model_class if self.class.model_class.present? # get the model class off of the model return @model.base_class if @model.present? # generate a model class class_name_without_resource.safe_constantize end
def model_id
def model_id @model.send id end
def model_key
With uncountable models route key appends an _index suffix (Fish->fish_index)
We use this instead of the route_key to maintain compatibility with uncountable models
This is used as the model class ID
def model_key model_class.model_name.plural end
def model_name
def model_name model_class.model_name end
def model_title
def model_title return name if @model.nil? the_title = @model.send title return the_title if the_title.present? model_id rescue name end
def name
def name default = class_name_without_resource.to_s.gsub('::', ' ').underscore.humanize return @name if @name.present? if translation_key && ::Avo::App.translation_enabled t(translation_key, count: 1, default: default).capitalize else default end end
def navigation_label
def navigation_label plural_name.humanize end
def order_actions
def order_actions return {} if ordering.blank? ordering.dig(:actions) || {} end
def ordering_host(**args)
def ordering_host(**args) Avo::Hosts::Ordering.new resource: self, options: self.class.ordering, **args end
def plural_name
def plural_name default = name.pluralize if translation_key && ::Avo::App.translation_enabled t(translation_key, count: 2, default: default).capitalize else default end end
def query_scope
def query_scope final_scope = resolve_query_scope.present? ? resolve_query_scope.call(model_class: model_class) : model_class authorization.apply_policy final_scope end
def record
def record @model end
def record_path
def record_path resource_path(model: model, resource: self) end
def records_path
def records_path resources_path(resource: self) end
def resource_description
def resource_description return instance_exec(&self.class.description) if self.class.description.respond_to? :call # Show the description only on the resource index view. # If the user wants to conditionally it on all pages, they should use a block. if view == :index return self.class.description if self.class.description.is_a? String end end
def route_key
def route_key class_name_without_resource.underscore.pluralize end
def scope
This is the search_query scope
def scope query_scope end
def singular_model_key
def singular_model_key model_class.model_name.singular end
def singular_name
def singular_name name end
def singular_route_key
def singular_route_key route_key.singularize end
def translation_key
def translation_key return "avo.resource_translations.#{class_name_without_resource.underscore}" if ::Avo::App.translation_enabled self.class.translation_key end
def underscore_name
def underscore_name return @name if @name.present? self.class.name.demodulize.underscore end
def valid_association_name(record, association_name)
def valid_association_name(record, association_name) get_record_associations(record).keys.find do |name| name == association_name end end
def valid_attachment_name(record, association_name)
def valid_attachment_name(record, association_name) association_exists = get_record_associations(record).keys.any? do |name| name == "#{association_name}_attachment" || name == "#{association_name}_attachments" end return association_name if association_exists end
def valid_model_class(model_class)
def valid_model_class(model_class) get_available_models.find do |m| m.to_s == model_class.to_s end end