Creating custom Modules

Basicly there are two ways to set up a module:

  • Use Alchemy as your Rails admin backend
  • Create a new Engine

1 Using Alchemy as your Rails admin backend

Hence every module is a subsection of a Rails application or a gem you can roll out your own admin backend if you like.

By using Alchemy’s backend interface you get a whole bunch of things:

  1. Authentication and Authorization
  2. A highly and fine grained customizable resource manager (CRUD interface)
  3. A nicely styled user interface

And it’s easy as this:


module Admin
  class YourResourcesController < Alchemy::Admin::ResourcesController
  end
end

You can overwrite the default controller actions and views as you like. An instance-variable named after the resource (i.e. @your_resource for YourResource) is defined for use in your views.

After you setting up your routes you have to take care for control access:

2 Authorization

Rights and roles are set in app/models/ability.rb. Just create the file if it doesn’t exist already.


# app/models/ability.rb
class Ability
  include CanCan::Ability

  def initialize(user)
    if !user.blank? && user.is_admin?
      can :manage, YourResource
      can :manage, :admin_your_resource
    end
  end

end

More information about authorization can be found in the docs of the cancan gem (https://github.com/ryanb/cancan/wiki/Defining-Abilities)

3 Mounting

3.1 For an engine:


# config/routes.rb
YourApp::Application.routes.draw do
  ...
  mount YourAlchemyModule::Engine => '/'
  mount Alchemy::Engine => '/'
end

3.2 For your apps resources:


# config/routes.rb
YourApp::Application.routes.draw do

  resources :your_resource

  namespace :admin do
    resources :your_resource
  end

  mount Alchemy::Engine => '/'
end

Due to Alchemy’s strong routes it is strongly recommended to mount your engine before Alchemy.

4 Registering the module

Last but not least the module needs to be registered to Alchemy CMS.

4.1 When using your host app:


# my_host_app/config/initializers/alchemy_modules.rb
Alchemy::Modules.register_module({
  name: 'name_of_your_module',
  order: 1,                             # The position in main navigation, if you have more than 1 module.
  navigation: {
    name: 'modules.products',           # The name in the main navigation (translated via I18n).
    controller: '/admin/products',      # The controller that will be used.
    action: 'index',                    # The controller action that will be used.
    icon: 'module_icon',                # Class of icon that will be rendered as navigation icon.
    sub_navigation: [
      {
        name: 'modules.products',       # The name for the subnavigation tab (translated via I18n).
        controller: '/admin/products',  # Controller that will be used.
        action: 'index'                 # Controller action that will be used.
      },
      {
        name: 'modules.variants',       # The name for the subnavigation tab (translated via I18n).
        controller: '/admin/variants',  # Controller that will be used.
        action: 'index'                 # Controller action that will be used.
      }
    ]
  }
})

As an alternative to the module icon you can pass:
image: '/alchemy/icon_of_your_module.png'

4.1.1 Translate your module names:

All module names are passed through I18n within a alchemy namespace. The name will be used as translation key. You should namespace your module name (with i.e. modules), to prevent conflicts.

Example:

Given a module name modules.products your translation has to be:


# config/locales/de.yml
de:
  alchemy:
    modules:
      products: Produkte

4.2 Using a Rails engine:


# my_engine/config/initializers/alchemy.rb
Alchemy::Modules.register_module({
  name: 'name_of_your_module',
  engine_name: 'name_of_your_engine'    # The engine_name set in your Rails::Engine class.
  order: 1,                             # The position in main navigation, if you have more than 1 module.
  navigation: {
    name: 'modules.products',           # The name in the main navigation (translated via I18n).
    controller: '/admin/products',      # The controller that will be used.
    action: 'index',                    # The controller action that will be used.
    icon: 'module_icon',                # Class of icon that will be rendered as navigation icon.
    sub_navigation: [
      {
        name: 'modules.products',       # The name for the subnavigation tab (translated via I18n).
        controller: '/admin/products',  # Controller that will be used.
        action: 'index'                 # Controller action that will be used.
      },
      {
        name: 'modules.variants',       # The name for the subnavigation tab (translated via I18n).
        controller: '/admin/variants',  # Controller that will be used.
        action: 'index'                 # Controller action that will be used.
      }
    ]
  }
})

# Loading authorization rules and register them to auth engine instance
Alchemy::Auth::Engine.get_instance.load(File.join(File.dirname(__FILE__), 'authorization_rules.rb'))

5 Get Ready!

Restart, point your browser to localhost:3000/admin/your_resources!