Customizing ActiveAdmin Form

At Dexcode, we love ActiveAdmin. We've been using it in a couple of projects and we love its simplicity and elegant design. In this article, we want to share our experience with ActiveAdmin as a way for us to contribute back to the Ruby on Rails community.

When customizing ActiveAdmin, we found that new developers often stumble on the ActiveAdmin DSL and its lack of documentation. However, customizing ActiveAdmin form should not be hard because the ActiveAdmin form is implemented based on Formtastic and in turn Formtastic is implemented based on Rails ActionView FormBuilder. So any Formtastic or rails helper code would work inside the ActiveAdmin form block.

Examples

Let's work through some examples, the below examples assume that we want to customize the form for User model.

Adding Hidden Field to ActiveAdmin Form

Let's say we have two types of users, admin users and normal users and we store this information in a role column as a string in the users table.

class User < ActiveRecord::Base  
  validates :role, format: { with: /\A(admin|normal)\z/ }

  def admin?
    role == 'admin'
  end

  def normal?
    role == 'normal'
  end
end  

And we want to create a form for admin users and normal users separately. Thus, we will need to add a hidden input field to the ActiveAdmin form to force the user to be an admin.

ActiveAdmin.register User, as: 'Admin' do  
  form do |f|
    f.hidden_field :role, value: 'admin'
    ...
  end
end  

As you can see, the Rails form helper hidden_field works in ActiveAdmin DSL, too.

Another way to do this is to use Formtastic syntax which is very similar to simple_form syntax.

ActiveAdmin.register User, as: 'Admin' do  
  form do |f|
    f.input :role, as: :hidden
    ...
  end
end  

Nested Resource has_one Workaround

Another problem that we often have is dealing with nested resource with has_one relationship. Let's say we have another model called Profile that stores the user profile. In the ActiveAdmin form, we want the user form to have profile information shown as a nested resource of the user form. The problem is that ActiveAdmin form only supports has_many attribute while the User and Profile information relationship is a has_one relationship. Thus, first we need to initialize the profile information as part of the user information and second, we want to disable removing profile from the user. So, we come up with this solution:

ActiveAdmin.register User do  
  form do |f|
    f.inputs "Profile", for: [:profile, f.object.profile || Profile.new] do |p|
      p.input :first_name
      p.input :last_name
    end
  end
end  

Hopefully, the above information helps.