Multiple Namespaces with ActiveAdmin

Active Admin is a Ruby on Rails gem for building administrative interfaces. There are plenty of tutorials out there showing how to customize the look & fill with the default namespace: AdminUser.

This tutorial will provide guidelines on how-to multiple interfaces using namespaces. Imaging you having administrators, agents and suppliers in your rails app and each group required different views and level of access to your application.

Disclaimer: This post shows how I came up with a solution to managing multiple namespaces but it might no be the best approach or the solution you need! Consider yourself warned.

Our admin interface will have 2 areas:

Add gems to gemfile:

gem 'activeadmin'
gem 'devise', '~>4.6.0'

Run bundle install

Create an AdminUser class to use with ActiveAdmin:

bin/rails g active_admin:install

We get an alert on a few things we need to do before continuing:

Ensure you have defined root_url to something in your config/routes.rb

Let’s create a dummy controller for now.

bin/rails g controller home index

and routes.rb should looks like:

Rails.application.routes.draw do
  root to: 'home#index'
  get 'home/index'
  devise_for :admin_users, ActiveAdmin::Devise.config

Now, migrate and seed your database before starting the server:

bin/rails db:migrate
bin/rails db:seed
bin/rails server

Visit http://localhost:3000/admin and log in as the default user:

Password: password

Note: if you havent configure mailer when devise was installed you may want to do:

Possible configuration for config/environments/development.rb:

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }


Create devise model:

bin/rails g devise AdminSupplierUser bin/rails db:migrate

Create SupplierAdminUser & password in seeds.rb

Note comment out AdminUser.create! before running

AdminSupplierUser.create!(email: '', password: 'password', password_confirmation: 'password') if Rails.env.development?

bin/rails db:seed

Create directory in app/admin_supplier

update config/initializers/active_admin.rb as follow:

 config.site_title = "ActiveAdmin MultiNamespaces"

  config.load_paths = [File.expand_path('app/admin', Rails.root), File.expand_path('app/admin_supplier', Rails.root)]

  config.default_namespace = :admin

config.namespace :admin do |admin|
  admin.site_title = "Admin Panel"
  admin.authentication_method = :authenticate_admin_user!
  admin.current_user_method = :current_admin_user
  admin.logout_link_path = :destroy_admin_user_session_path

config.namespace :supplier do |supplier|
  supplier.site_title = "Active Supplier Panel"
  supplier.authentication_method = :authenticate_admin_supplier_user!
  supplier.current_user_method = :current_admin_supplier_user
  supplier.logout_link_path = :destroy_admin_supplier_user_session_path

Update routes.rb

Rails.application.routes.draw do

  root to: 'home#index'
  get 'home/index'

  devise_for :admin_users, ActiveAdmin::Devise.config
  devise_for :admin_supplier_users,ActiveAdmin::Devise.config.merge({path: '/supplier'})

Create app/admin_supplier/dashboard.rb

ActiveAdmin.register_page "Dashboard", namespace: :admin_supplier do
  menu priority: 1, label: proc { I18n.t("active_admin.dashboard") }

  content title: proc { I18n.t("active_admin.dashboard") } do
    div class: "blank_slate_container", id: "dashboard_default_message" do
      span class: "blank_slate" do
        span I18n.t("active_admin.dashboard_welcome.welcome")
        small I18n.t("active_admin.dashboard_welcome.call_to_action")

  end # content

By now you should have your 2 interfaces up and running at:

One more thing you need to do is to redirect supplier logout to the supplier path as currently it will default to the Admin login page.

Create app/admin_supplier/override.rb with the following snippet:

ActiveAdmin::Devise::SessionsController.class_eval do
  def after_sign_out_path_for(resource)
    case resource
    when :admin_supplier_user then supplier_root_url
    else super

This will override the default method when the resource is :admin_supplier_user.

And that’s it - hope you find it helpful.

I guess another approach is using cancan gem that is probably a subject for a completely different post!!!


comments powered by Disqus