Multiple file upload with HTML5 and RailsAdmin (Ruby on Rails)

16 October 2013

Yesterday I spent a few hours working on adding multiple file upload capabilities to the administrative panel of a website I am working on. The administrative panel of the website is built using RailsAdmin. RailsAdmin is a Rails engine that provides an easy-to-use interface for managing your data.

I needed the upload functionality for the Gallery section of the website. Each photo gallery has many photos and the website owner should be able to upload with ease multiple photos for each gallery. The ideal solution for this use case is to have a file upload field that accepts multiple files, so that the administrator could select a number of pictures from their computer and upload with a single click.

The last time I had to develop this functionality, I did it by integrating SWFUpload (JavaScript Library that wraps Flash Player's upload function) with the Symfony framework.

This time I decided to use the HTML5 file input tag, with the multiple attribute. A quick search returned a blog post, quite close to what I need - Multiple file upload with Rails 3.2, paperclip, html5 and no javascript. What was left was to integrate that functionality with RailsAdmin's custom actions.

Models

The first step is to create an Album and Photo models.

class Album < ActiveRecord::Base
  attr_accessible :title
  has_many :photos

  accepts_nested_attributes_for :photos, :allow_destroy => true
  attr_accessible :photos_attributes
end

class Photo < ActiveRecord::Base
  attr_accessible :caption, :album_id, :file
  belongs_to :album

  has_attached_file :file, :styles => { :detailed => "1920x1920>", :thumb => "100x100>" }
end

Having those two models, RailsAdmin should automatically detect them and provide a simple upload functionality for the file field inside the Photo model.

RailsAdmin Custom Action

The next step is to create a custom controller and view for the Multiple File upload action. I created a new Gem using the gist from RailsAdmin's wiki:

rails plugin new rails_admin_multiple_upload -m https://gist.github.com/bbenezech/1621146/raw/5268788e715397bf476c83d76d335f152095e659/rails_admin_action_creator --skip-gemfile --skip-bundle -T -O -S -J --full

After that we amend the custom view for the action:

= simple_form_for(rails_admin.multiple_upload_url(@abstract_model.to_param), html: { multipart: true }) do |f|
  = f.input :album_id, :as => :hidden, :input_html => { :name => "album_id", :value => @object.id }
  = file_field_tag('album_photos_file', multiple: true, name: "album[photos_attributes][][file]")
  = f.submit :submit, value: 'Upload', name: 'Upload', :class => 'btn btn-primary'

... as well as the rails_admin_multiple_upload.rb file

class MultipleUpload < Base
  RailsAdmin::Config::Actions.register(self)
  register_instance_option :member do
    true
  end

  register_instance_option :link_icon do
    'icon-upload'
  end

  register_instance_option :http_methods do
    [:get, :post]
  end

  register_instance_option :controller do
    Proc.new do
      @response = {}

      if request.post?
        @album = Album.find_by_id(params[:album_id])
        @album.update_attribute(:photos_attributes, params[:album][:photos_attributes])
      end

      render :action => @action.template_name
    end
  end
end

We add the Gem to the project's Gemfile:

gem 'rails_admin_multiple_upload', :path => '../rails_admin_multiple_upload'

RailsAdmin initialiser configuration

The last bit is to add the custom action to the member actions of the Album model. We only want to have the multiple upload button for the Album model, therefore we add the only directive. This we do at the RailsAdmin initialiser: config/initialisers/rails_admin.rb

RailsAdmin.config do |config|
  config.actions do
    dashboard
    index
    new

    multiple_upload do
      only Album
    end

    show
    edit
    delete
  end
end

Subscribe to our newsletter to receive our latest posts

Just enter your e-mail address below to receive a notification for updates on our blog.


blog comments powered by Disqus

Follow us on