Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: eject controllers #3377

Merged
merged 4 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
338 changes: 1 addition & 337 deletions app/controllers/avo/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,340 +1,4 @@
module Avo
class ApplicationController < ::ActionController::Base
if defined?(Pundit::Authorization)
Avo::ApplicationController.include Pundit::Authorization
elsif defined?(Pundit)
Avo::ApplicationController.include Pundit
end

include Avo::InitializesAvo
include Avo::CommonController
include Avo::ApplicationHelper
include Avo::UrlHelpers
include Avo::Concerns::Breadcrumbs
include Avo::Concerns::FindAssociationField

protect_from_forgery with: :exception
around_action :set_avo_locale
around_action :set_force_locale, if: -> { params[:force_locale].present? }
before_action :init_app
before_action :set_active_storage_current_host
before_action :set_resource_name
before_action :_authenticate!
before_action :set_authorization
before_action :set_container_classes
before_action :add_initial_breadcrumbs
before_action :set_view
before_action :set_sidebar_open
before_action :set_stylesheet_assets_path

rescue_from Avo::NotAuthorizedError, with: :render_unauthorized
rescue_from ActiveRecord::RecordInvalid, with: :exception_logger

helper_method :_current_user, :resources_path, :resource_path, :new_resource_path, :edit_resource_path, :resource_attach_path, :resource_detach_path, :related_resources_path, :turbo_frame_request?, :resource_view_path, :preview_resource_path
add_flash_types :info, :warning, :success, :error

def exception_logger(exception)
respond_to do |format|
format.html { raise exception }
format.json {
render json: {
errors: (exception.respond_to?(:record) && exception.record.present?) ? exception.record.errors : [],
message: exception.message,
traces: exception.backtrace
}, status: ActionDispatch::ExceptionWrapper.status_code_for_exception(exception.class.name)
}
end
end

# This is coming from Turbo::Frames::FrameRequest module.
# Exposing it as public method
def turbo_frame_request?
super
end

private

# Get the pluralized resource name for this request
# Ex: projects, teams, users
def resource_name
return params[:resource_name] if params[:resource_name].present?

return controller_name if controller_name.present?

begin
request.path
.match(/\/?#{Avo.root_path.delete("/")}\/resources\/([a-z1-9\-_]*)\/?/mi)
.captures
.first
rescue
end
end

def related_resource_name
params[:related_name]
end

# Gets the Avo resource for this request based on the request from the `resource_name` "param"
# Ex: Avo::Resources::Project, Avo::Resources::Team, Avo::Resources::User
def resource
resource = Avo.resource_manager.get_resource @resource_name.to_s.camelize.singularize

return resource if resource.present?

Avo.resource_manager.get_resource_by_controller_name @resource_name
end

def related_resource
# Find the field from the parent resource
field = find_association_field(resource: @resource, association: params[:related_name])

return field.use_resource if field&.use_resource.present?

reflection = @record.class.reflect_on_association(field&.for_attribute || params[:related_name])

reflected_model = reflection.klass

Avo.resource_manager.get_resource_by_model_class reflected_model
end

def set_resource_name
@resource_name = resource_name
end

def set_related_resource_name
@related_resource_name = related_resource_name
end

def set_resource
raise ActionController::RoutingError.new "No route matches" if resource.nil?

@resource = resource.new(view: params[:view].presence || action_name.to_s, user: _current_user, params: params)

set_authorization
end

def detect_fields
@resource.detect_fields
end

def set_related_resource
raise Avo::MissingResourceError.new(related_resource_name) if related_resource.nil?

action_view = action_name.to_sym

# Get view from params unless actions is index or show or forms...
# Else, for example for detach action we want the view from params to can fetch the correct fields
# This logic avoid the following scenario:
# When a has many field is rendered the action is index and params[:view] is show or edit but we want to
# keep @view as index for the related_resource
# Same do not happen with other actions except the list below.
view = if action_view.in?([:index, :show, :new, :edit, :create])
action_view
else
params[:view].presence || action_view
end

@related_resource = related_resource.new(
params: params,
view: view,
user: _current_user,
record: @related_record
).detect_fields
end

def set_record
id = if @resource.model_class.primary_key.is_a?(Array) && params.respond_to?(:extract_value)
params.extract_value(:id)
else
params[:id]
end

@record = @resource.find_record(id, query: model_scope, params:)
@resource.hydrate(record: @record)
end

def set_related_record
association_name = BaseResource.valid_association_name(@record, params[:related_name])
@related_record = if @field.is_a? Avo::Fields::HasOneField
@record.send association_name
else
@related_resource.find_record params[:related_id], query: @record.send(association_name), params: params
end
@related_resource.hydrate(record: @related_record)
end

def model_scope
# abort @resource.inspect
@resource.class.find_scope
end

# Force actions to have specific view
unless defined? VIEW_ACTION_MAPPING
VIEW_ACTION_MAPPING = {
update: :edit,
create: :new
}
end

def set_view
@view = Avo::ViewInquirer.new(VIEW_ACTION_MAPPING[action_name.to_sym] || action_name)
end

def set_record_to_fill
@record_to_fill = if @view.new?
@resource.model_class.new
elsif @view.edit?
@record
end

# If resource.record is nil, most likely the user is creating a new record.
# In that case, to access resource.record in visible and readonly blocks we hydrate the resource with a new record.
# TODO: commented this
@resource.hydrate(record: @record_to_fill) if @resource.record.nil?
end

def fill_record
# We have to skip filling the the record if this is an attach action
return if is_attach_action?

@record = @resource.fill_record(@record_to_fill, cast_nullable(model_params), extra_params: extra_params)
assign_default_value_to_disabled_fields if @view.create?
end

def is_attach_action?
params[model_param_key].blank? && params[:related_name].present? && params[:fields].present?
end

def assign_default_value_to_disabled_fields
@resource.get_field_definitions.select do |field|
field.is_disabled? && field.visible? && !field.computed
end.each do |field|
# Get the default value from the field default definition
# If there is no default value specified on the resource, get the value from the record (DB, Callbacks, etc.)
default_value = field.default || @record.send(field.id)
field.fill_field @record, field.id, default_value, params
end
end

def authorize_base_action
class_to_authorize = @record || @resource.model_class

authorize_action class_to_authorize
end

def authorize_action(class_to_authorize, action = nil)
# Use the provided action or figure it out from the request
action_to_authorize = action || action_name

@authorization.set_record(class_to_authorize).authorize_action action_to_authorize.to_sym
end

def _authenticate!
instance_eval(&Avo.configuration.authenticate)
end

def render_unauthorized(exception)
flash[:notice] = t "avo.not_authorized"

redirect_url = if request.referrer.blank? || (request.referrer == request.url)
root_url
else
request.referrer
end

redirect_to(redirect_url)
end

def set_authorization
# We need to set @resource_name for the #resource method to work properly
set_resource_name
@authorization = if @resource
@resource.authorization(user: _current_user)
else
Services::AuthorizationService.new _current_user
end
end

def set_container_classes
contain = true

if Avo.configuration.full_width_container
contain = false
elsif Avo.configuration.full_width_index_view && action_name.to_sym == :index && self.class.superclass.to_s == "Avo::ResourcesController"
contain = false
end

@container_classes = contain ? "2xl:container 2xl:mx-auto" : ""
end

def add_initial_breadcrumbs
instance_eval(&Avo.configuration.initial_breadcrumbs) if Avo.configuration.initial_breadcrumbs.present?
end

def model_param_key
@resource.form_scope
end

# Sets the locale set in avo.rb initializer or if to something that the user set using the `?set_locale=pt-BR` param
def set_avo_locale(&action)
locale = Avo.configuration.default_locale

if params[:set_locale].present?
locale = params[:set_locale]
Avo.configuration.locale = locale
end

I18n.with_locale(locale, &action)
end

# Temporary set the locale and reverting at the end of the request.
def set_force_locale(&action)
I18n.with_locale(params[:force_locale], &action)
end

def set_sidebar_open
value = cookies["#{Avo::COOKIES_KEY}.sidebar.open"]
@sidebar_open = value.blank? || value == "1"
end

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

def set_stylesheet_assets_path
# Prefer the user's tailwind config if it exists, otherwise use the default one from Avo
@stylesheet_assets_path = if Rails.root.join("config", "avo", "tailwind.config.js").exist?
"avo.tailwind"
elsif Avo::PACKED
"/avo-assets/avo.base"
else
"avo.base"
end
end

def choose_layout
if turbo_frame_request?
"avo/blank"
else
"avo/application"
end
end

def authenticate_developer_or_admin!
raise_404 unless Avo::Current.user_is_developer? || Avo::Current.user_is_admin?
end

def raise_404
raise ActionController::RoutingError.new "No route matches"
end
class ApplicationController < BaseApplicationController
end
end
Loading
Loading