Ruby on Rails admin area scaffolding

Each and every Ruby on Rails website typically has its own admin area. Ryan Bates (a well-known person in Rails world) says in one of his first railscasts that it is a good idea to have the same code base for admin and public area of the website. Another approach could take place, I think. And this is why:

  • usually, admin area has more actions in controllers and more complex data output with variety of fields;
  • public area usually has simpler output;
  • having common code base for admin and public area leads to code complexity and increases the amount of access permission checks.

Thus, it is more sensible to separate admin area from public area. This way public area code will be simpler and cleaner and admin area code will do only what it's meant for. Of course, there are gems, such as activeadminrails_admin, etc. They allow to generate full-featured admin area. But implementation of your own custom admin area sometimes is more suitable, rather than customization of existing complex mechanism.

I'd like to tell you how to separate admin area from public area by example.

So, let's create a sample rails application:

rails new sample

You can also specify ruby version if you are using rvm

cd sample && rvm --create --ruby-version use ruby-2.0.0-p247

Let's remove turbolinks from Gemfile right away and run bundle install --without production

We should also remove //= require turbolinks from app/assets/javascripts/application.js
And we will change assets structure for our needs:

app
+-/assets
  +-/javascripts
    +-/admin - we will have client scripts for admin area here
    +-/application - we will have client scripts for public area here
    +-admin.js
    +-application.js
  +-/stylesheets
    +-/admin - we'll have stylesheets for admin area here
    +-/application - we'll have stylesheets for public area here
    +-admin.css.scss
    +-application.css.scss

And the contents of the main files are listed below:

# app/assets/javascripts/admin.js
//= require jquery
//= require jquery_ujs
//= require_tree ./admin
# app/assets/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require_tree ./application
# app/assets/stylesheets/admin.css.scss
/*
 *= require_self
 *= require_tree ./admin
 */
# app/assets/stylesheets/application.css.scss
/*
 *= require_self
 *= require_tree ./application
 */

We should specify some assets precomplication options to make it work in production:

# config/environments/production.rb
  config.assets.precompile += %w(admin.js admin.css)

Let's create admin layout now:

# app/views/layouts/admin.html.erb
<!DOCTYPE html>
<html>
<head>
  <title>Sample</title>
  <%= stylesheet_link_tag    "admin", media: "all" %>
  <%= javascript_include_tag "admin" %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= yield %>

</body>
</html>

You can implement it in haml if you wish. I just customized default Rails layout.

We are about to deal with controllers, views and models now and that is the most interesting part... What would we like to get in the end?

  • Controllers should be in app/controllers/admin folder and should have Admin:: namespace.
  • Helpers should be in app/helpers/admin folder and also should have Admin:: namespace.
  • Resource routes in routes.rb should be nested withing :admin namespace.
  • Views should be in subfolders of app/views/admin folder.
  • Models should not have Admin namespace and should be utilized without it everywhere.
  • Redirects in controllers should point to admin pages, e.g. redirect_to [:admin, @post].
  • Edit form should be submitted to a proper path within admin area, so we should use form_for [:admin, @post].
  • All links should lead to admin area sections, so we should use [:admin, @post], admin_posts_path, edit_admin_post_path(@post) and new_admin_post_path in views and controllers.
  • Tests should also take into account all those peculiarities, use Admin namespace and proper route paths where it is neccessary.

Standard Ruby on Rails scaffold generators can't do that. They will either create a model with namespace or will use incorrect paths and will put files to the wrong places. I found only one single article which describes the process of generating of such admin structure by hand. I wanted to share my own more simple way to prepare the structure of admin area described above. But while I was writing this post I decided to make my own generators for admin area scaffolding and I created a gem then. This is how rails-admin-scaffold gem was born. I hope it'll be useful for someone, though it is still in progress and works only with Rails 4.

This gem automates all those manual actions described above. rails-admin-scaffold gem also supports the following at the moment:

  • Rails 4 only;
  • test::unit tests generating;
  • assets are generated in admin subfolders;
  • it supports jbuilder;
  • it supports haml.

I plan to implement rspec, minitest and probably formtastic/simple_form support.

It is really simple to use:

  1. Add gem 'rails-admin-scaffold', 'x.x.x' to your Gemfile
  2. Run bundle install
  3. Now you can scaffold admin controllers, views, etc with something like:
    bin/rails g admin:scaffold_controller Post title:string content:text published:boolean

It doesn't generate models, but the fields specified are used in controller.

I should note, that it makes sense to create a separate base controller class AdminController which is inherited from ApplicationController and has some authentication filters, layout, etc configured. All controllers in admin area could be easily inherited from it. Maybe I'll add this option to rails-admin-scaffold gem soon.

I'll appreciate your feedback.

Useful links: