Repository URL to install this package:
|
Version:
1.0.0.pre ▾
|
require 'active_admin/resource_collection'
module ActiveAdmin
# Namespaces are the basic organizing principle for resources within Active Admin
#
# Each resource is registered into a namespace which defines:
# * the namespaceing for routing
# * the module to namespace controllers
# * the menu which gets displayed (other resources in the same namespace)
#
# For example:
#
# ActiveAdmin.register Post, namespace: :admin
#
# Will register the Post model into the "admin" namespace. This will namespace the
# urls for the resource to "/admin/posts" and will set the controller to
# Admin::PostsController
#
# You can also register to the "root" namespace, which is to say no namespace at all.
#
# ActiveAdmin.register Post, namespace: false
#
# This will register the resource to an instantiated namespace called :root. The
# resource will be accessible from "/posts" and the controller will be PostsController.
#
class Namespace
RegisterEvent = 'active_admin.namespace.register'.freeze
attr_reader :application, :resources, :name, :menus
def initialize(application, name)
@application = application
@name = name.to_s.underscore.to_sym
@resources = ResourceCollection.new
register_module unless root?
build_menu_collection
end
# Register a resource into this namespace. The preffered method to access this is to
# use the global registration ActiveAdmin.register which delegates to the proper
# namespace instance.
def register(resource_class, options = {}, &block)
config = find_or_build_resource(resource_class, options)
# Register the resource
register_resource_controller(config)
parse_registration_block(config, resource_class, &block) if block_given?
reset_menu!
# Dispatch a registration event
ActiveAdmin::Event.dispatch ActiveAdmin::Resource::RegisterEvent, config
# Return the config
config
end
def register_page(name, options = {}, &block)
config = build_page(name, options)
# Register the resource
register_page_controller(config)
parse_page_registration_block(config, &block) if block_given?
reset_menu!
config
end
def root?
name == :root
end
# Returns the name of the module if required. Will be nil if none
# is required.
#
# eg:
# Namespace.new(:admin).module_name # => 'Admin'
# Namespace.new(:root).module_name # => nil
#
def module_name
return nil if root?
@module_name ||= name.to_s.camelize
end
# Unload all the registered resources for this namespace
def unload!
unload_resources!
reset_menu!
end
# Returns the first registered ActiveAdmin::Resource instance for a given class
def resource_for(klass)
resources[klass]
end
# Override from ActiveAdmin::Settings to inherit default attributes
# from the application
def read_default_setting(name)
application.public_send name
end
def fetch_menu(name)
@menus.fetch(name)
end
def reset_menu!
@menus.clear!
end
# Add a callback to be ran when we build the menu
#
# @param [Symbol] name The name of the menu. Default: :default
# @param [Proc] block The block to be ran when the menu is built
#
# @return [void]
def build_menu(name = DEFAULT_MENU, &block)
@menus.before_build do |menus|
menus.menu name do |menu|
block.call(menu)
end
end
end
# The default logout menu item
#
# @param [ActiveAdmin::MenuItem] menu The menu to add the logout link to
# @param [Fixnum] priority The numeric priority for the order in which it appears
# @param [Hash] html_options An options hash to pass along to link_to
#
def add_logout_button_to_menu(menu, priority = 20, html_options = {})
if logout_link_path
html_options = html_options.reverse_merge(method: logout_link_method || :get)
menu.add id: 'logout', priority: priority, html_options: html_options,
label: ->{ I18n.t 'active_admin.logout' },
url: ->{ render_or_call_method_or_proc_on self, active_admin_namespace.logout_link_path },
if: :current_active_admin_user?
end
end
# The default user session menu item
#
# @param [ActiveAdmin::MenuItem] menu The menu to add the logout link to
# @param [Fixnum] priority The numeric priority for the order in which it appears
# @param [Hash] html_options An options hash to pass along to link_to
#
def add_current_user_to_menu(menu, priority = 10, html_options = {})
if current_user_method
menu.add id: 'current_user', priority: priority, html_options: html_options,
label: -> { display_name current_active_admin_user },
url: -> { auto_url_for(current_active_admin_user) },
if: :current_active_admin_user?
end
end
protected
def build_menu_collection
@menus = MenuCollection.new
@menus.on_build do |menus|
build_default_utility_nav
resources.each do |resource|
resource.add_to_menu(@menus)
end
end
end
# Builds the default utility navigation in top right header with current user & logout button
def build_default_utility_nav
return if @menus.exists? :utility_navigation
@menus.menu :utility_navigation do |menu|
add_current_user_to_menu menu
add_logout_button_to_menu menu
end
end
# Either returns an existing Resource instance or builds a new one.
def find_or_build_resource(resource_class, options)
resources.add Resource.new(self, resource_class, options)
end
def build_page(name, options)
resources.add Page.new(self, name, options)
end
# TODO: replace `eval` with `Class.new`
def register_page_controller(config)
eval "class ::#{config.controller_name} < ActiveAdmin::PageController; end"
config.controller.active_admin_config = config
end
def unload_resources!
resources.each do |resource|
parent = (module_name || 'Object').constantize
name = resource.controller_name.split('::').last
parent.send(:remove_const, name) if parent.const_defined? name
# Remove circular references
resource.controller.active_admin_config = nil
if resource.is_a?(Resource) && resource.dsl
resource.dsl.run_registration_block { @config = nil }
end
end
@resources = ResourceCollection.new
end
# Creates a ruby module to namespace all the classes in if required
def register_module
unless Object.const_defined? module_name
Object.const_set module_name, Module.new
end
end
# TODO replace `eval` with `Class.new`
def register_resource_controller(config)
eval "class ::#{config.controller_name} < ActiveAdmin::ResourceController; end"
config.controller.active_admin_config = config
end
def parse_registration_block(config, resource_class, &block)
config.dsl = ResourceDSL.new(config, resource_class)
config.dsl.run_registration_block(&block)
end
def parse_page_registration_block(config, &block)
PageDSL.new(config).run_registration_block(&block)
end
end
end