I recently wanted to be able to upload a small file and then store it as a field in the database via an Active Admin interface in a Rails app. The solution is pretty simple, but it was tricky to figure out.
In my case, the file was a small piece of firmware. For this example, we’ll have a simple table with only two interesting columns containing the name of the file and the contents of the file itself. An example migration is as follows:
class CreateFirmwareImages < ActiveRecord::Migration
def change
create_table :firmware_images do |t|
t.string : firmware_image_filename
t.binary :firmware_image, :limit => 10.megabyte
t.timestamps
end
end
end
Create File-Upload Input Field
The first step is to add an `as: :file` for the form input field:
form do |f|
f.inputs "Firmware" do
f.input :firmware_image, as: :file
end
f.actions
end
We don’t have an input field for the filename since we’ll get that from the file when the user uploads it.
Getting the File Contents
To get access to the file contents, we’ll need to manually read it. No automagic here. This means we’ll need to use custom create()
and update()
methods in our Active Admin controller. Inside those methods, you can get access to the uploaded file like so:
attrs = permitted_params[:firmware_image]
filename = attrs[:firmware_image].original_filename
contents = attrs[:firmware_image].read
And that’s the crux of it.
Cleaning Things Up
I don’t want to show the raw file contents (which is the default) on my index and attributes tables. So I also added something like this, which allows me to show just the filename.
index do
column :firmware_image_filename
column :updated_at
default_actions
end
show do
attributes_table do
row :firmware_image_filename
end
end
Putting it all together, the result looks something like this:
ActiveAdmin.register FirmwareImage do
permit_params :firmware_image
config.filters = false
index do
column :firmware_image_filename
column :updated_at
default_actions
end
form do |f|
f.inputs "Firmware" do
f.input :firmware_image, as: :file
end
f.actions
end
show do
attributes_table do
row :firmware_image_filename
end
end
controller do
def create
attrs = permitted_params[:firmware_image]
@firmware_image = FirmwareImage.create()
@firmware_image[:firmware_image_filename] = attrs[:firmware_image].original_filename
@firmware_image[:firmware_image] = attrs[:firmware_image].read
if @firmware_image.save
redirect_to admin_firmware_image_path(@firmware_image)
else
render :new
end
end
def update
attrs = permitted_params[:firmware_image]
@firmware_image = FirmwareImage.where(id: params[:id]).first!
@firmware_image.firmware_level = attrs[:firmware_level]
@firmware_image[:firmware_image_filename] = attrs[:firmware_image].original_filename
@firmware_image[:firmware_image] = attrs[:firmware_image].read
if @firmware_image.save
redirect_to admin_firmware_image_path(@firmware_image)
else
render :edit
end
end
end
end
Just what I had in mind!
Hi thanks for the post. I am trying to use paperclip with activeadmin where i have 5 file columns and all 5 have to be unique and present. The thing is when i select attachment for only 1 column the errors are not displayed at all.
How to do this?
`default_actions` is no longer provided in ActiveAdmin 1.x. Use `actions` instead.