ICMS Backend
ICMS Backend provides a uniform administration interface for modifying application resources. It comes with a modular authentication and authorization system, CRUD functionality and an Asset Manager for handling files of any kind.
Asset Manager
The Asset Manager is an important part of ICMS Backend. It lets you manage all of your assets in one location and share them between resources. In the documentation for the Assetable plugin below we explain how to add the asset manager to your models.
Any type of file can be handled by the Asset Manager but there are additional features for handling common multimedia files with resizing/focus, metadata and much more for images and automatic screenshots for videos, etc.
Alot of effort has gone into making the Asset Manager a useful tool, rich with too many features to list here. However, any installation of ICMS Backend has the Asset Manager available in the top right hand corner so it's easy to get started and see what it offers.
Authentication
Authentication in ICMS Backend is handled by a pluggable authentication adapter. Two adapters are included with the framework and others can be added as needed.
Included Authentication Adapters
None Adapter
This is the default (dummy) adapter that implements the methods required by the interface but doesn't actually do anything. This gets you up and running quickly but allows anyone to access the administration interface without any kind of authentication.
Devise Adapter
The second adapter included is the Device Adapter that simply integrates the well known Devise gem with the ICMS framework.
Authorization
Authorization, just like authentication, is handled by a pluggable adapter. Two adapters are included and others can be addded if needed.
With authorization enabled you will find a Roles section in the administration interface where permissions can be granted to specific roles (that subsequently are associated with an authorizer).
Included Authorization Adapters
None Adapter
This is the default (dummy) adapter that implements the methods required by the interface but doesn't actually do anything. This gets you up and running quickly but allows anyone with access to the administration interface to take any action without authorization.
Cancan Adapter
An adapter integrating the cancancan gem with the ICMS framework.
Plugins
Assetable
Any model that uses the plugin assetable
can make use of the built in Asset Manager. A typical use case might look something like this:
class BlogPost < ActiveRecord::Base
icms do
assetable
end
has_photo :cover, folder: "Blog Post Photos"
end
The assetable plugin injects a number of helper methdods into the model:
has_attachment(name, options = {})
Specifies a one-to-one association with the IcmsBackend::AssetManager::Asset class. It allows you to add an asset regardless of type to your class, taking advantage of the Asset Manager interface for uploading/selecting assets.
A has_one association called name will be created, allowing access to the asset on the class instances.
Options
:accepted
The name of a MIME type group that can be defined in an initializer:
config.asset_manager.mime_types.my_mime_types = ['audio/mpeg3', 'application/pdf']
# Defaults to: IcmsBackend.config.asset_manager.mime_types.attachment
:folder
Specify the root folder for chosing assets from when selecting an asset for this association. It defaults to IcmsBackend::AssetManager::Configuration::DEFAULT_FOLDER_NAME
that can be configured through IcmsBackend.config.asset_manager.default_folder_name
If the folder doesn't exist it will be created as a new root level folder. Root level folders cannot be deleted through the Asset Manager interface to ensure the integrity of this layer of organization.
Usage Examples:
has_attachment :certificate, accepted: :my_mime_types
has_attachment :curriculum, folder: 'users'
has_attachments(name, options = {})
Specifies a one-to-many association with the IcmsBackend::AssetManager::Asset
class. It allows adding assets to any class, taking advantage of the Asset Manager interface for uploading/selecting assets.
A has_many association called name will be created, allowing access to the asset on the class instances.
Options
:max
The maximum number of assets that you may pick from the Asset Manager.
See the documentation for has_attachment for more available options.
Usage Examples:
has_attachments :certifications, max: 5
has_audio(name, options = {})
Specifies a one-to-one association with the IcmsBackend::AssetManager::Audio
class. It allows you to add an audio file to your class, taking advantage of the Asset Manager interface for uploading/selecting audio files.
A has_one association called name will be created, allowing access to the audio asset on the class instances.
Options
:accepted
The name of a MIME type group that can be defined in an initializer:
config.asset_manager.mime_types.my_mime_types = ['audio/mpeg3']
# Defaults to: IcmsBackend.config.asset_manager.mime_types.audio
:folder
Specify the root folder for chosing audios from when selecting a video for this association. It defaults to IcmsBackend::AssetManager::Configuration::DEFAULT_FOLDER_NAME
but can be configured through IcmsBackend.config.asset_manager.default_folder_name
If the folder doesn't exist it will be created as a new root level folder. Root level folders cannot be deleted through the Asset Manager interface to ensure the integrity of this layer of organization.
Usage Examples:
has_audio :product_demo, accepted: [:mp3]
has_audio :overview, folder: :products
has_audios(name, options = {})
Specifies a one-to-many association with the IcmsBackend::AssetManager::Audio
class. It allows you to add audio files to your class, taking advantage of the Asset Manager interface for uploading/selecting audio files.
A has_many association called name will be created, allowing access to the audio asset on the class instances.
Options
:max
The maximum number of audio files that you may pick from the Asset Manager.
See the documentation for has_audio for more available options.
Usage Examples:
has_audios :gallery, max: 3
has_document(name, options = {})
Specifies a one-to-one association with the IcmsBackend::AssetManager::Document
class. It allows you to add a document to your class, taking advantage of the Asset Manager interface for uploading/selecting documents.
A has_one association called name will be created, allowing access to the document asset on the class instances.
Options
:accepted
The name of a MIME type group that can be defined in an initializer:
config.asset_manager.mime_types.my_mime_types = ['application/pdf', 'text/plain']
# Defaults to: IcmsBackend.config.asset_manager.mime_types.document
:folder
Specify the root folder for chosing documents from when selecting a document for this association. It defaults to IcmsBackend::AssetManager::Configuration::DEFAULT_FOLDER_NAME
but can be configured through IcmsBackend.config.asset_manager.default_folder_name
If the folder doesn't exist it will be created as a new root level folder. Root level folders cannot be deleted through the Asset Manager interface to ensure the integrity of this layer of organization.
Usage Examples:
has_document :data_sheet, accepted: :my_mime_types
has_document :curriculum, folder: 'users'
has_documents(name, options = {})
Specifies a one-to-many association with the IcmsBackend::AssetManager::Document
class. It allows adding documents to any class, taking advantage of the Asset Manager interface for uploading/selecting documents.
A has_many association called name will be created, allowing access to the document asset on the class instances.
Options
:max
The maximum number of documents that you may pick from the Asset Manager.
See the documentation for has_document for more available options.
Usage Examples:
has_documents :certifications, max: 5
has_photo(name, options = {})
Specifies a one-to-one association with the IcmsBackend::AssetManager::Photo
class. It allows for adding a photo to any class, taking advantage of the Asset Manager interface for uploading/selecting photos.
A has_one association called name will be created, allowing access to the photo asset on the class instances.
Options
:accepted
The name of a MIME type group that can be defined in an initializer:
config.asset_manager.mime_types.my_mime_types = [image/jpeg', 'image/png']
# Defaults to: IcmsBackend.config.asset_manager.mime_types.photo
:folder
Specify the root folder for chosing photos from when selecting a photo for this association. It defaults to IcmsBackend::AssetManager::Configuration::DEFAULT_FOLDER_NAME
but can be configured through IcmsBackend.config.asset_manager.default_folder_name
.
If the folder doesn't exist it will be created as a new root level folder. Root level folders cannot be deleted through the Asset Manager interface to ensure the integrity of this layer of organization.
:versions
Specify a hash of versions that will be created when a photo is chosen from the Asset Manager. The key becomes the name of the version and the value is expected to be a string on the format "[width]x[height]".
The cropping of the original photo will be made intelligently, using the focus point from the original and the format specified for the version. This is a design choice that probably works fine 99% of the time. In rare cases where the result is not what was expected it is always possible to insert a new, modified, original and create version from that one instead.
Example Usage:
has_photo :front, folder: :products, accepted: :my_mime_types
has_photo :back, versions: { small: '640x480', medium: '800x600', large: '1024x768' }
has_photos(name, options = {})
Specifies a one-to-many with the IcmsBackend::AssetManager::Photo
class. It allows adding photos to any class, taking advantage of the Asset Manager interface for uploading/selecting photos.
A has_many association called name will be created, allowing access to the photo asset on the class instances.
Options
:max
The maximum number of photos that you may pick from the Asset Manager.
See the documentation for has_photo for more available options.
Usage Examples:
has_photos :gallery, max: 10
has_video(name, options = {})
Specifies a one-to-one association with the IcmsBackend::AssetManager::Video
class. It allows you to add a video to your class, taking advantage of the Asset Manager interface for uploading/selecting videos.
A has_one association called name will be created, allowing access to the video asset on the class instances.
Options
:accepted
The name of a MIME type group that can be defined in an initializer:
config.asset_manager.mime_types.my_mime_types = ['audio/mpeg3']
# Defaults to: IcmsBackend.config.asset_manager.mime_types.video
:folder
Specify the root folder for chosing videos from when selecting a video for this association. It defaults to IcmsBackend::AssetManager::Configuration::DEFAULT_FOLDER_NAME
but can be configured through IcmsBackend.config.asset_manager.default_folder_name
If the folder doesn't exist it will be created as a new root level folder. Root level folders cannot be deleted through the Asset Manager interface to ensure the integrity of this layer of organization.
Usage Examples:
has_video :product_demo, accepted: :my_mime_types
has_video :overview, folder: :products
has_videos(name, options = {})
Specifies a one-to-many association with the IcmsBackend::AssetManager::Video
class. It allows you to add videos to your class, taking advantage of the Asset Manager interface for uploading/selecting videos.
A has_many association called name will be created, allowing access to the video asset on the class instances.
Options
:max
The maximum number of videos that you may pick from the Asset Manager.
See the documentation for has_video for more available options.
Usage Examples:
has_videos :gallery, max: 3
Authorizer
The Authorizer plugin defines a model as an entity that can be used to authorize others. Examples of this might be a User or AdminUser model (or both).
The plugin doesn't require any options and the usage is as simple as a line in the icms block of your model:
icms do
authorizer
end
Authorizable
The Authorizable plugin defines a model as something that can be authorized. This, most likely, will be the majority of your models such as blog posts, comments, users, etc.
The plugin usage is as simple as a line in the icms block of your model:
icms do
authorizable
end
Options
:permissions
Every authorizable has basic CRUD permissions but, if needed, you may specify other, custom, permissions for each resource. For example:
class Invoice < ActiveRecord::Base
icms do
authorizable permissions: [:print, :send]
end
end
The additional permissions will automatically appear in the Roles section for the current resource. For example:
Resource | Create | Read | Update | Delete | Send | |
---|---|---|---|---|---|---|
Invoice | ▢ | ▣ | ▢ | ▢ | ▣ | ▣ |
User | ▣ | ▣ | ▣ | ▣ | ▣ |
Dashboard
ICMS Backend introduces the concept of dashboards. A dashboard is the glue between the administration interface and the application. It describes how a model should be presented, which fields should be included in the form, which fields can be searched, etc.
A simplified example dashboard might look like:
class PostDashboard < IcmsBackend::BaseDashboard
# A hash that describes the type of each of the model's fields.
ATTRIBUTE_TYPES = {
title: Field::String.with_options(searchable: { attribute_name: :translations_title }),
content: Field::Text.with_options(searchable: { attribute_name: :translations_content }),
cover: Field::Asset,
}
# An array of attributes that will be displayed on the model's index page.
COLLECTION_ATTRIBUTES = [
:id,
:title,
]
# An array of attributes that will be displayed on the model's show page.
SHOW_COMPONENTS = [
{ type: :titled_show_attribute, name: :title },
{ type: :titled_show_attribute, name: :content },
]
# An array of components that will be displayed on the model's form (new and edit) pages.
FORM_COMPONENTS = [
:title,
:content,
]
end
In the context of the Dashboard
, a number of methods are available to provide customization possibilities for the current application. You may find that you need to add custom actions or buttons in various places of the interface or perhaps you want to move the dashboard resource to another place in the menu tree.
Below is a list of the most important helper methods but for a full list it is recommended to take a look directly at the class IcmsBackend::BaseDashboard
.
Dashboard Helper Methods
resource_action(name, options = {}, &block)
Adds an action to the show/edit/index views of the resource.
resource_action
is a convenient way of adding custom resource actions for a Dashboard.
Options
:add_to_index
A boolean determining the visibility of the button on the row of the resource in the index list. Defaults to false.
:confirm
A confirmation message that needs to be accepted for the action to take place.
:if
A boolean or proc that determines the visibility of the resource action button in the IcmsBackend interface. If a proc is given, the current view context will be passed as a parameter and the proc is expected to return a boolean. Defaults to true, always showing the button.
:icon
The name of a material design icon that appears next to the button label. Valid icon names can be found at Material Icons. By default no icon is shown.
:label
The label for the button. It defaults to name
:method
The HTTP method used for submitting the form of the resource action. Defaults to GET
:mode
The button mode. It can be either :link, :button or :submit. The :method
option only applies to :button and :submit :mode.
:link renders a normal link, :button render a normal button while :submit renders a button that submits the form with all parameters using the method :method
. Defaults to :button
:type
A symbol representing the type of action (and route to generate). It can be either :member or :collection. Defaults to :member
Usage Examples:
The simplest use of resource_action
is by passing it the name of an action. This causes IcmsBackend to look for a "my_show" in the "IcmsBackend::Products" controller.
class ProductDashboard < IcmsBackend::BaseDashboard
resource_action :my_show
end
A more complex example adding a "Statistics" button to the show view of products:
class ProductDashboard < IcmsBackend::BaseDashboard
resource_action :download_statistics,
icon: 'timeline',
if: -> (view, resource) { view.action_name == 'show' },
label: 'Statistics'
do
@product = requested_resource
# Show download statistics for this product in a custom view.
end
end
collection_action(name, options = {}, &block)
Adds a a collection action to the index view of the resource.
A collection action, like the name suggests, operates on a collection of records. A button will appear in the IcmsBackend interface, calling this action with the selected resource IDs in a hidden form element.
This method is used internally for plugins such as Publishable that needs to add "Publish" and "Unpublish" actions but it is also convenient for quickly adding custom actions that present information about or modify a collection of records. collection_action
is usually called from within a Dashboard.
Options
:always_active
A boolean determining if the collection action button is active or not, regardless if any records are selected or not. Default to false, allowing the button to toggle based upon the current selection.
:icon
The name of a material design icon that appears next to the button label. Valid icon names can be found at Material Icons. By default no icon is shown.
:if
A boolean or proc that determines the visibility of the collection action button in the IcmsBackend interface. If a proc is given, the current view context will be passed as a parameter and the proc is expected to return a boolean. Defaults to true, always showing the button.
:label
The label for the collection action button. It defaults to name
:method
The HTTP method used for submitting the form of the collection action. Defaults to POST
Usage Examples:
The simplest use of collection_action
is by passing it the name of an action. This causes IcmsBackend to look for a "favorites" action in the "IcmsBackend::Products" controller.
class ProductDashboard < IcmsBackend::BaseDashboard
collection_action :favorites
end
A more complex example:
class ProductDashboard < IcmsBackend::BaseDashboard
collection_action :touch, label: 'Touch us!', if: -> (view) { true }, method: :post do
products = Product.find params[:batch_action_ids]
products.update_all updated_at: DateTime.now
redirect_to '/admin/products', notice: "#{products.count} products updated"
end
end
custom_action(name, options = {}, &block)
Adds a custom action to the expanding button of the resource views.
A custom action doesn't operate on any particular record but rather serves as a convenient way for adding a custom action to present any needed information about the current collection.
custom_action
is usually called within a Dashboard.
Options
:icon
The name of a material design icon that constitutes the button. Valid icon names can be found at Material Icons.
:if
A boolean or proc that determines the visibility of the custom action button in the IcmsBackend interface. If a proc is given, the current view context will be passed as a parameter and the proc is expected to return a boolean. Defaults to true, always showing the button.
:tooltip
The tooltip for the custom action button. It defaults to name
Usage Examples:
The simplest use of custom_action
tt> is by passing it the name of an action.
class ProductDashboard < IcmsBackend::BaseDashboard
custom_action :favorites
end
sidebar_menu_parent
A method that returns the name of the parent in the menu tree. It can be overridden but by default looks like this:
def sidebar_menu_parent
:content
end
resource_class
A method that returns the class of the current resource. This needs to be overridden if the name cannot be inferred from the name of the dashboard. By default it looks like this:
def resource_class
name.gsub('Dashboard', '').constantize
end
Page
IcmsBackend::Page
connects a dashboard to a model instance and provides the context needed in order to render the administration interface. This is mostly transparent to the developer so we will not discuss it here.
Field
ICMS Backend also introduces the concept of "fields". A field is a class that extends IcmsBackend::Field::Base
and, in the very simplest form, might look something like this:
# icms_backend/field/date.rb
module IcmsBackend
module Field
class Date < Base
end
end
end
In the Dashboard section above we saw the use of a couple of fields in the ATTRIBUTE_TYPES
hash. This is the main use of fields - we define a dashboard that describes which fields a model has and then where they should be presented. For example we can see the :title
attribute in the COLLECTION_ATTRIBUTES
. This will tell ICMS Backend that we want to show the attribute title
in the index page of the resource and since we have declared title to be a Field::String
we know how to deal with it.
Every field type has a partial for each render context (index, show, form and search) that takes care of rendering the field. For example, Field::String
has the following partial for the search context:
# app/views/fields/string/_search.html.haml
= f.input field.search_form_attribute_name,
as: :string,
required: false,
label: field.human_attribute_name,
input_html: { value: field.search_form_value(params), class: field.html_class }