Godmin

Gem Version Build Status Code Climate

Godmin is an admin engine for Rails 4+.

Installation

Godmin supports two common admin scenarios:

  1. Standalone installation
  2. Engine installation

Standalone installation

Use for admin-only applications, or for architectures where the admin lives in its own app. Typically, you want to access the admin section at localhost:3000.

Add the gem to the application's Gemfile:

gem "godmin"

Run the install generator:

$ bin/rails generate godmin:install

Godmin should be up and running at localhost:3000

Engine installation

Use when the admin is part of the same codebase as the main application. Typically you want to access the admin section at localhost:3000/admin.

Generate a mountable engine:

$ bin/rails plugin new admin --mountable

Add the engine to the application's Gemfile:

gem "admin", path: "admin"

Mount the engine in the application's config/routes.rb:

mount Admin::Engine, at: "admin"

Add the gem to the engine's gemspec, admin/admin.gemspec:

s.add_dependency "godmin", "~> x.x.x"

Run the install generator within the scope of the engine, i.e. note the leading admin/:

$ admin/bin/rails generate godmin:install

Godmin should be up and running at localhost:3000/admin

Installation artefacts

Installing Godmin does a number of things to the Rails application.

A config/initializers/godmin.rb is created:

Godmin.configure do |config|
  config.namespace = nil
end

If Godmin was installed inside an engine, as in the previous section, the namespace is the underscored name of the engine, e.g. "admin".

The config/routes.rb file is modified as such:

Rails.application.routes.draw do
  godmin do
  end
end

Resource routes placed within the godmin block are automatically added to the default navigation, and set up to work with batch actions. More on this in later sections.

The application controller is modified as such:

class ApplicationController < ActionController::Base
  include Godmin::Application
end

If Godmin was installed inside an engine, a require "godmin" statement is placed in {namespace}/lib/{namespace}.rb.

And finally, the app/views/layouts folder is removed by default, so as not to interfere with the Godmin layouts. It can be added back in case you wish to override the built in layouts.

Getting started

Godmin deals primarily with resources. A resource is something that can be administered through the Godmin user interface, often a Rails model. Let's say the application has an Article model with attributes such as title, body and published. To get going quickly, we can use a generator:

$ bin/rails generate godmin:resource article title published

Or for an engine install:

$ admin/bin/rails generate godmin:resource article title published

This does a number of things.

First, it inserts a route in the config/routes.rb file that looks like this:

godmin do
  resources :articles
end

Second, it creates a controller that looks something like this:

class ArticlesController < ApplicationController
  include Godmin::Resource

  def attrs_for_index
    [:title, :published]
  end

  def attrs_for_form
    [:title, :published]
  end
end

Using attrs_for_index we can control what fields are displayed in the table listing, and using attrs_for_form we can control what fields are available in the new and edit forms. We can, for instance, add the body field to attrs_for_form to make it appear in forms:

def attrs_for_form
  [:title, :body, :published]
end

By now we have a basic admin interface for managing articles.

Controllers

We have already seen two controller methods at play: attrs_for_index and attrs_for_form. Now we will look at four additional controller concepts, namely:

  • Scopes
  • Filters
  • Batch actions
  • Resource fetching

Scopes

Scopes are a way of sectioning resources, useful for quick navigation, and can be created as follows:

class ArticlesController < ApplicationController
  include Godmin::Resource

  scope :unpublished, default: true
  scope :published

  def scope_unpublished(resources)
    resources.where(published: false)
  end

  def scope_published(resources)
    resources.where(published: true)
  end
end

Filters

Filters offer great flexibility when it comes to searching for resources.

Filters can be created as follows:

class ArticlesController < ApplicationController
  include Godmin::Resource

  filter :title

  def filter_title(resources, value)
    resources.where("title LIKE ?", "%#{value}%")
  end
end

There are four types of filters: string, select, multiselect and checkboxes, specified using the as parameter.

When using select or multiselect, a collection must be specified. The collection must conform to the format used by Rails options_for_select helpers. It can be either an array consisting of name/value tuples, or a collection of ActiveRecords.

filter :category, as: :select, collection: -> { [["News", 1], ["Posts", 2]] }

When specifying a collection of ActiveRecords, two additional parameters, option_text and option_value can be specified. They default to to_s and id respectively.

filter :category, as: :select, collection: -> { Category.all }, option_text: "title"

Batch actions

Batch actions can be created as follows:

class ArticlesController < ApplicationController
  include Godmin::Resource

  batch_action :publish
  batch_action :unpublish
  batch_action :destroy, confirm: true

  def batch_action_publish(resources)
    resources.each { |r| r.update_attributes(published: true) }
  end

  ...
end

In addition, batch actions can be defined per scope using only and except:

batch_action :publish, only: [:unpublished]
batch_action :unpublish, only: [:published]

If you wish to implement your own redirect after a batch action, return false afterwards:

def batch_action_publish(resources)
  resources.each { |r| r.update_attributes(published: true) }
  redirect_to articles_path(scope: published) and return false
end

Resource fetching

Resources are made available to the views through instance variables. The index view can access the resources using @resources while show, new and edit can access the single resource using @resource.

In order to modify what resources to fetch, there are three methods that can be overridden per resource controller:

  • resource_class
  • resource_relation
  • resources

To change the class name of the resource from the default based on the controller name:

class ArticlesController
  include Godmin::Resource

  def resource_class
    FooArticle
  end
end

To scope resources, e.g. based on the signed in user:

class ArticlesController
  include Godmin::Resource

  def resources_relation
    admin_user.articles
  end
end

To add to the resources query, e.g. to change the default order:

class ArticlesController
  include Godmin::Resource

  def resources
    super.order(author: :desc)
  end
end

Redirecting

By default the user is redirected to the resource show page after create and update. To change this, there are four controller methods that can be overridden: redirect_after_create, redirect_after_update, redirect_after_save, and redirect_after_destroy.

For instance, to have the article controller redirect to the index page after both create and update:

class ArticlesController
  include Godmin::Resource

  def redirect_after_save
    articles_path
  end
end

Or, to have the article controller redirect to the index page after create and the edit page after update:

class ArticlesController
  include Godmin::Resource

  def redirect_after_create
    articles_path
  end

  def redirect_after_update
    edit_article_path(@resource)
  end
end

If you wish to change the behaviour for every resource controller, consider creating a common resource controller that your other controllers can inherit from:

class ResourceController < ApplicationController
  include Godmin::Resource

  def redirect_after_save
    resource_class.model_name.route_key.to_sym
  end
end

Views

It is easy to override view templates and partials in Godmin, both globally and per resource. All you have to do is place a file with an identical name in your app/views directory. For instance, to override the godmin/resource/index.html.erb template for all resources, place a file under app/views/resource/index.html.erb. If you only wish to override it for articles, place it instead under app/views/articles/index.html.erb.

If you wish to customize the content of a table column, you can place a partial under app/views/{resource}/columns/{column_name}.html.erb, e.g. app/views/articles/columns/_title.html.erb. The resource is available to the partial through the resource variable.

Oftentimes, the default form provided by Godmin doesn't cut it. The godmin/resource/_form.html.erb partial is therefore one of the most common to override per resource.

Likewise, the godmin/shared/_navigation.html.erb partial can be overridden to build a custom navigation bar.

The full list of templates and partials that can be overridden can be found here

Models

Authentication

Multiple authentication scenarios are supported. Godmin comes with a built in authentication solution that can be used to sign in to the admin section via the admin interface. In addition, when running an admin engine, it is possible to set up a shared authentication solution so that administrators can sign in via the main app.

Simple authentication

This example uses the built in authentication solution. Authentication is isolated to the admin section and administrators sign in via the admin interface.

Godmin comes with a generator that creates an admin user model and enables the built in authentication:

$ bin/rails generate godmin:authentication
$ bin/rake db:migrate

Please note: when installing to an admin engine, the migration needs to be moved to the main app before it can be found by db:migrate. Rails has a solution in place for this:

$ admin/bin/rails generate godmin:authentication
$ bin/rake admin:install:migrations
$ bin/rake db:migrate

The generated model looks like this:

class AdminUser < ActiveRecord::Base
  include Godmin::Authentication::User

  def self.
    :email
  end
end

By default the model is generated with an email field as the login column. This can changed in the migration prior to migrating if, for instance, a username column is more appropriate.

The following route is generated:

resource :session, only: [:new, :create, :destroy]

Along with a sessions controller:

class SessionsController < ApplicationController
  include Godmin::Authentication::Sessions
end

Finally, the application controller is tweaked to look something like this:

class ApplicationController < ActionController::Base
  include Godmin::Application
  include Godmin::Authentication

  def admin_user_class
    AdminUser
  end
end

Authentication is now required when visiting the admin section.

Shared authentication

This example uses Devise to set up a shared authentication solution between the main app and an admin engine. Administrators sign in and out via the main application.

There is no need to run a generator in this instance. Simple add the authentication module to the admin application controller like so:

module Admin
  class ApplicationController < ActionController::Base
    include Godmin::Application
    include Godmin::Authentication
  end
end

Provided you have User model set up with Devise in the main application, override the following three methods in the admin application controller:

module Admin
  class ApplicationController < ActionController::Base
    include Godmin::Application
    include Godmin::Authentication

    def authenticate_admin_user
      authenticate_user!
    end

    def admin_user
      current_user
    end

    def admin_user_signed_in?
      user_signed_in?
    end
  end
end

That's it. The admin section is now authenticated using Devise.

Authorization

In order to enable authorization, authentication must first be enabled. See the previous section. The Godmin authorization system is heavily inspired by Pundit and implements the same interface.

Add the authorization module to the application controller:

class ApplicationController < ActionController::Base
  include Godmin::Application
  include Godmin::Authentication
  include Godmin::Authorization

  ...
end

Policies can be generated using the following command:

$ bin/rails generate godmin:policy article

This file app/policies/article_policy.rb will be created:

class ArticlePolicy < Godmin::Authorization::Policy
end

Permissions are specified by implementing methods on this class. Two methods are available to the methods, user and record, the signed in user and the record being authorized. An implemented policy can look something like this:

class ArticlePolicy < Godmin::Authorization::Policy
  def index?
    true
  end

  def show?
    true
  end

  def create?
    user.editor?
  end

  def update?
    user.editor? && record.unpublished?
  end

  def destroy?
    update?
  end
end

That is, everyone can list and view articles, only editors can create them, and only unpublished articles can be updated and destroyed.

Localization

Godmin supports localization out of the box. Strings can be translated both globally and per resource, similar to how views work.

For a list of translatable strings, look here.

For instance, to translate the godmin.batch_actions.select_all string globally:

godmin:
  batch_actions:
    select_all: {translation}

Or, translate for a specific resource:

godmin:
  articles:
    batch_actions:
      select_all: {translation}

In addition, all scopes, filters and batch actions that are added, can be localized:

godmin:
  articles:
    batch_actions:
      publish: {translation}
      unpublish: {translation}
    filters:
      labels:
        title: {translation}
    scopes:
      unpublished: {translation}
      published: {translation}

Godmin comes with built in support for English and Swedish.

There is a view helper available named translate_scoped that can be used in overridden views. Please see the source code for information on how to use it.

Contributors

https://github.com/varvet/godmin/graphs/contributors

License

Licensed under the MIT license. See the separate MIT-LICENSE file.