Uploading Files in Rails’ Active Admin

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!

Conversation
  • Jayden says:

    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?

  • Karol Majek says:

    `default_actions` is no longer provided in ActiveAdmin 1.x. Use `actions` instead.

  • Comments are closed.