Uploading Files In ActiveAdmin
Published: Apr 5, 2022
Last updated: Apr 5, 2022
This post will demonstrate how to upload files to ActiveAdmin.
Source code can be found here
Prerequisites
- It is expected that you follow on from a previous setup like the one explored in my previous blog post "ActiveAdmin With Ruby On Rails 7".
Getting started
It is expected that you follow the "Getting Started" section from my previous post "ActiveAdmin With Ruby On Rails 7" (but for a project named demo-upload-csv-to-active-admin
).
Once you are at the point of seeing the /admin
route from that post, come back here to finish the rest.
The last things that we want to do:
- Create a Template model (that we will populate in the database from a CSV file).
- Create a page for our CSV upload.
- Create a file for our CSV helper file.
- Create a CSV file for our test upload.
# Create our "Template" model $ bin/rails g model Template name:string description:string author:string # Create a page for our CSV upload $ touch app/admin/templates.rb # Create a service folder for the CSV converter $ mkdir app/services $ touch app/services/csv_helper.rb test.csv # Migrate changes for our template $ bin/rails db:migrate
At this stage, our project is now ready to start populating.
Updating our Template model
We will add some simple validations for our file app/models/template.rb
here:
class Template < ApplicationRecord validates :name, presence: true validates :description, presence: true validates :author, presence: true end
Setting our CSV data
Our CSV data will map to our name
, description
and author
columns respectively.
"POST A","DESCRIPTION A","AUTHOR A" "POST B","DESCRIPTION B","AUTHOR B" "POST C","DESCRIPTION C","AUTHOR C" "POST D","DESCRIPTION D","AUTHOR D" "POST E","DESCRIPTION E","AUTHOR E"
The idea is that each row will end up populating the data.
Writing out our admin template page
In app/admin/templates.rb
, we will register a page "Template":
ActiveAdmin.register_page 'Template' do action_item only: :index do link_to 'Upload CSV', action: 'upload_csv' end page_action :upload_csv do render 'admin/csv/upload_csv' end page_action :import_csv, method: :post do templates = CsvHelper.convert_to_templates(params[:dump][:file]) Template.transaction do templates.each(&:save!) end redirect_to({ action: :index }, notice: 'CSV imported successfully!') rescue StandardError redirect_to({ action: :index }, flash: { error: 'CSV imported failed! Check the template is correct or contact a developer.' }) end end
There are a few things that we are doing here:
- Creating a page at the route
/admin/template
. - Adding a link to the page at the top of the page for uploading a CSV that will redirect to
admin/template/upload_csv
. - The route
admin/template/upload_csv
will render theapp/views/admin/csv/upload_csv.html.erb
view (that we will create next). - The
page_action
method will be called when the user clicks on the link to upload a CSV.
The last action is most important. It will attempt to convert our CSV file to Template instances and then a transaction will attempt to upload them to the database (which we will also create soon).
If successful, the user will be redirected back to /admin/template
with a success banner message displayed.
If the user is unsuccessful, the user will be redirected back to /admin/template
with a failure banner message.
Next, let's tackle the view.
Creating our upload CSV view
Create the file app/views/admin/csv/upload_csv.html.erb
and add the following:
<%= form_for :dump, :url=>{:action=>"import_csv"}, :html => { :multipart => true } do |f| %> <table> <tr> <td> <label for="dump_file"> Select a CSV File : </label> </td> <td><%= f.file_field :file %></td> </tr> <tr> <td><%= submit_tag 'Submit' %></td> </tr> </table> <% end %>
The above code will create a form that allows for a file, then on submission uploads that to the /admin/template/import_csv
route that we have our handler for.
Finally, we need to add in the CsvHelper
class.
Adding the CsvHelper class
Under app/services/csv_helper.rb
, add the following:
class CsvHelper class << self def convert_to_templates(csv_data) templates = [] csv_file = csv_data.read CSV.parse(csv_file) do |row| name, description, author = row templates << Template.new(name: name, description: description, author: author) end templates end end end
Here we are adding a class method to the CsvHelper
class. This method takes CSV data from the upload, converts each row to a Template
instance, pushes it to an array of templates and finally returns it.
The returned templates will start a transaction for them to be inserted (as you can see in the previous code for the form submission handler).
Testing the CSV upload
At this point, we can get to our admin panel and test things out.
Run bin/rails s
to start the server, head to /admin
and login with the admin@example.com
and password
details.
Once logged in, you can head to /admin/template
and click on the Upload CSV
link.
Template page
The following page will display the form for your CSV file upload.
Template form for the file upload
Once you select the test.csv
file that we created, you will be redirected to the /admin/template/import_csv
route with a success message (unless there is an issue).
Success
If you have an issue, you will see the error message:
Error
Summary
Today's post demonstrated how to upload a file to ActiveAdmin and process that upload.
Resources and further reading
Photo credit: bernardhermant
Uploading Files In ActiveAdmin
Introduction