Code.Art.Web

Code.Art.Web

Profile Picture

Lorefnon

Dealing with JSON data in Active Admin

Abstract

While the default form fields of Active Admin are decent for most use cases, there are special cases like JSON data stored in relational databases, for which the built in controls might prove to be inadequate. This post explains how to handle the same.

Many a times, depending on the requirements, it makes sense to store unstructured json data in database fields. PostgreSQL recognizes this requirement and provides a dedicated json field that automatically handles JSON validation. As has been outlined in the RoR Guides , it is pretty simple to take advantage of this feature from Rails. However if you also use ActiveAdmin to manage your admin interface, you will quickly find out that library Formtastic that ActiveAdmin uses to manage its forms, leaves a lot to be desired when it comes to JSON editing support.

In this post we outline a simple approach to improve JSON editing support in ActiveAdmin using the excellent JSON editor widget by Jos de Jong. It is worth pointing out that our implementation has very little to do with PostgreSQL and may be used without modifications if you are storing JSON in say MySQL text fields. Of course you will need to handle server side validation yourself in that case.

The source code for the post is available on Github.

Let us have a simple product model with following schema:

class CreateProducts < ActiveRecord::Migration
  def change
    create_table :products do |t|
      t.string :name
      t.text :description
      t.json :metadata
      t.timestamps
    end
  end
end

You may expect providing admin support for this model will just be a matter of adding a file app/admin/product.rb:

ActiveAdmin.register Product do
  permit_params :name, :description, :metadata
end

However the moment you try to create a new instance, you will be greeted with an error message:

Formtastic unknown input error

So basically Formtastic has no input field pre-configured for json field. A rudimentary workaround is fairly simple - We explicitly ask it to use a textarea for metadata field

ActiveAdmin.register Product do

  permit_params :name, :description, :metadata

  form do |f|
    f.inputs do
      f.input :name
      f.input :description
      f.input :metadata, as: :text
    end
    f.actions
  end

end

This does the job:

Form with explicitly specified textarea

But seriously, if you have to edit this json very frequently or manage large json entries, a simple textarea is not an ideal solution. Plus if you accidentally enter some invalid json, You will be provided with a feedback only post submission:

Error in JSON field JSON validation error

The JSON editor widget by Jos de Jong provides a lot better json editing interface. You can try it out online.

If you like what you see, you will be pleased to find that the widget is pretty easy to integrate right inside ActiveAdmin.

Let us first configure our form to add a class to the json field so that we can handle json input fields in a generic fashion.

ActiveAdmin.register Product do

  permit_params :name, :description, :metadata

  form do |f|
    f.inputs do
      f.input :name
      f.input :description
      f.input :metadata, as: :text, input_html: { class: 'jsoneditor-target' }
    end
    f.actions
  end

end

Next we will need to download the relevant files and add to our vendor directory. Alternatively installation instructions for npm and bower are available as well.

I have already changed the files to use sprockets urls, so you can grab the files from the repo.

Next we modify the active_admin.js.coffee:

#= require active_admin/base
#= require jsoneditor
#= require jsoneditor_activeadmin_integration

Once we have the required files in place, integration is pretty simple - app/assets/javascripts/jsoneditor_activeadmin_integration:

$ ->

  $('.jsoneditor-target').each ->

    target = $ this

    container = $('<div class="jsoneditor-container">')
      .insertAfter target

    editor = new JSONEditor container[0],
      modes: ['code', 'form', 'text', 'tree', 'view']
      change: ->
        target.val editor.get()

    editor.set(
      try
        JSON.parse target.val()
    )

    target.hide()

This simply hides the textarea for json field, and adds a json editor widget. When the editor is updated, the hidden textarea is updated with the new value - so our form continues to work just as expected, without Formtastic having to be aware of the widget at all.

I had to explicitly override some of the conflicting styles from ActiveAdmin which were messing up the Editor Widget css:

.jsoneditor-container, .jsoneditor-contextmenu {
    table {
        width: auto;
        margin: 0;
    }

    .jsoneditor {
        background: white;
    }

    button, button:hover, .menu button, .menu button:hover {
        background: none;
        text-shadow: none;
        box-shadow: none;
        border-radius: 0;
    }
}

.jsoneditor-container {
    margin-left: 20%;
    width: 80%;
}

And we are pretty much done: Widget integrated with Active Admin

I realize that the default styling of the widget sticks out a bit against the default styling of ActiveAdmin page, but all that is needed to rectify is a few CSS rules which I leave as an exercise for the reader.

As always, any feedback and suggestions are more than welcome.

comments powered by Disqus
Separator line
Separator line
Lorefnon

Full stack web developer and polyglot programmer with strong interest in dynamic languages, web application development and user experience design.


Strong believer in agile methodologies, behaviour driven development and efficacy of open source technologies.


© 2013 - 2015 Gaurab Paul


Code licensed under the The MIT License. Content and Artwork licensed under CC BY-NC-SA.


The opinions expressed herein are my personal viewpoints and may not be taken as professional recommendations from any of my previous or current employers.


Site is powered by Jekyll and graciously hosted by Github