Images and Audio Preview in Active Admin
This is a small piece of code that extends active admin to show previews of images and audio on the index, edit, and show pages. It's very straightforward and very, very easy to implement.
repo: https://github.com/Rob117/active-admin-uploads
Why
I was recently working on a project where I needed a portable solution for enabling image and audio previews in active admin. The admins needed to be able to click on any given piece of audio to hear it, or an image preview to see it full size. They also needed this information available in the show, index, and edit views. This is the code that I distilled to perform that function. The full walkthrough is at the bottom.
Note: This code is not very Safari friendly, so I strongly recommend Chrome or Firefox for working with active admin (and also in general).
The Code
Module EnhancedUploader
# We grab the form, then the object from the form. We try to then show the
# content of that object
def input_audio(f, property)
f.input property, hint: audio_content(f.object, property)
end
def input_image(f, property)
f.input property, hint: image_content(f.object, property)
end
# We simply grab an object and check to see if our property exists on it.
# If it does, display the object
def audio_content(object, property)
if object.persisted? && object.respond_to?(property)
audio_tag object.send(property), controls: true
else
content_tag(:span, 'No Current Audio')
end
end
def image_content(object, property)
if object.persisted? && object.respond_to?(property)
image_tag object.send(property), height: 150
else
content_tag(:span, 'No Current Image')
end
end
end
Inputs Explanation
First, we'll start with the input form options
def input_audio(f, property)
f.input property, hint: audio_content(f.object, property)
end
def input_image(f, property)
f.input property, hint: image_content(f.object, property)
end
So, in order to understand what this code does, you have to understand what a hint is in active admin. When you edit something in active admin, it allows you to give some context as to what that object might be. You typically specify that with the hint: param. For example, you could write some text next to a field called 'credit card' on an input form that says 'application only accepts visa.', and it would show that next to the input field.
Let us assume we have a user profile picture that we want to display a preview of when we edit it on a form. We also have a audio sample of the user saying 'hello' that we would like to be playable on the form. The code for the input image and audio would look something like this:
# f is a form
form do |f|
extend EnhancedUploader
input_image f, :profile_picture
input_audio f, :hello_audio
end
Please check the section "The Use" for a minimal, guided, working example.
Audio and Image Content methods
Next, we'll explain what the following audio and image rendering code does:
def audio_content(object, property)
if object.persisted? && object.respond_to?(property)
audio_tag object.send(property), controls: true
else
content_tag(:span, 'No Current Audio')
end
end
def image_content(object, property)
if object.persisted? && object.respond_to?(property)
image_tag object.send(property), height: 150
else
content_tag(:span, 'No Current Image')
end
end
This code is much easier to explain. In each method, we accept an object. First, we check that it is persisted (saved to the DB), because if it isn't there's nothing to show or render - we cannot render data that we do not have.
Next, we check to make sure that the object can actually respond to the method that we want. It wouldn't be a good idea to try to render something that the object doesn't have! For example, before we try to display a profile_photo, we should make sure that the model actually has a profile_photo field that we can show.
Lastly, we simply render an html5-compliant image link or audio player with controls. The code in the show section would look something like this:
show do
extend EnhancedUploader
attributes_table do
row :profile_photo do |row_object|
image_content row_object, :profile_photo
end
row :hello_audio do |row_object|
audio_content row_object, :hello_audio
end
end
end
Walkthrough
Laying Foundation
rails new demo
rails g model User name:string location:string
rails db:create db:migrate
Now we add active admin and devise
In your gemfile, add the lines
gem 'activeadmin'
gem 'devise'
bundle
rails generate devise:install
rails g active_admin:install
rails db:migrate db:seed
rails s
Go to localhost:3000/admin
, login with
username: admin@example.com
password: password
create file at app/admin/user.rb, and paste in this content:
ActiveAdmin.register User do
permit_params :name, :location
# Show the essential data in the index
index do
selectable_column # we can select columns for batch actions
column :id
column :name
column :location
column :created_at
column :updated_at
actions
end
# When you click on the show for any individual item, this data is rendered
show do
attributes_table do # display the following attributes
row :id
row :name
row :location
row :created_at
row :updated_at
end
end
# When you click on edit, this form is rendered
form do |f|
f.semantic_errors
f.inputs do
f.input :name
f.input :location
end
f.actions
end
end
Go to http://localhost:3000/admin/users
and confirm that we can create, delete, and edit our basic users.
Adding CarrierWave
Time to add an image uploader and an audio uploader. First, let's include our library that will manage data display for us. Move the following file to lib/enhanced_uploader
+git file+
Add the following to your gemfile:
gem 'carrierwave', '~> 1.0'
bundle
make two uploaders, one for profile_photo and one for hello_audio
rails g uploader profile_photo
rails g uploader hello_audio
Add both uploaders to the user model
rails g migration add_profile_photo_to_users profile_photo:string
rails g migration add_hello_audio_to_users hello_audio:string
rails db:migrate
Open app/models/user.rb file and mount uploaders
class User < ApplicationRecord
mount_uploader :profile_photo, ProfilePhotoUploader
mount_uploader :hello_audio, HelloAudioUploader
end
Replace app/admin/user.rb with the following (we aren't showing the enchanced uploader quite yet):
ActiveAdmin.register User do
permit_params :name, :location, :profile_photo, :hello_audio
# Show the essential data in the index
index do
selectable_column
column :id
column :name
column :location
column :profile_photo
column :hello_audio
column :created_at
column :updated_at
actions
end
# When you click on the show for any individual item, this data is rendered
show do
attributes_table do
row :id
row :name
row :location
row :profile_photo
row :hello_audio
row :created_at
row :updated_at
end
end
# When you click on edit, this form is rendered
form do |f|
f.semantic_errors
f.inputs do
f.input :name
f.input :location
f.inputs :profile_photo
f.inputs :hello_audio
end
f.actions
end
end
We just added the fields. Restart your server and access your users page.
Create a user if you need to.
Notice that on index, show, and edit that the fields for profile_photo and hello_audio are blank. This is to be expected - we haven't uploaded anything yet!
Upload a small image and a small audio clip.
Notice that after we've uploaded it you can only view the path names and not anything inside the file.
To include our 'library', we only need make one small change, in config/application.rb:
require_relative 'boot'
require 'rails/all'
Bundler.require(*Rails.groups)
module Blogly
class Application < Rails::Application
config.autoload_paths += %W(#{config.root}/lib) # Add this line!
end
end
Now, simply change your admin/user.rb file to this final code:
ActiveAdmin.register User do
permit_params :name, :location, :profile_photo, :hello_audio
# Show the essential data in the index
index do
extend EnhancedUploader # include uploader
selectable_column
column :id
column :name
column :location
column :profile_photo do |row_object|
image_content row_object, :profile_photo
end
column :hello_audio do |row_object|
audio_content row_object, :hello_audio
end
column :created_at
column :updated_at
actions
end
# When you click on the show for any individual item, this data is rendered
show do
extend EnhancedUploader # include uploader
attributes_table do
row :id
row :name
row :location
row :profile_photo do |item|
image_content item, :profile_photo
end
row :hello_audio do |item|
audio_content item, :hello_audio
end
row :created_at
row :updated_at
end
end
# When you click on edit, this form is rendered
form do |f|
extend EnhancedUploader # include uploader
f.semantic_errors
f.inputs do
f.input :name
f.input :location
input_image f, :profile_photo
input_audio f, :hello_audio
end
f.actions
end
end
Refresh your server, and head to the users page. Now you should see previews of the audio and image that you uploaded on each index, show, and edit page! Success!
Top comments (1)
Great work, Rob.