# Uploading Files In ActiveAdmin

> See how to upload files to ActiveAdmin using this example that uploads a CSV file and populates data to the database.

- Canonical: https://dennisokeeffe.com/blog/2022-04-05-uploading-files-in-active-admin
- Published: 2022-04-05
- Updated: 2022-04-05
- Tags: ruby, ruby-on-rails

This post will demonstrate how to upload files to [ActiveAdmin](https://activeadmin.info/).

Source code can be found [here](https://github.com/okeeffed/demo-upload-csv-to-active-admin)

## Prerequisites

1. 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"](https://blog.dennisokeeffe.com/blog/2022-03-12-active-admin-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"](https://blog.dennisokeeffe.com/blog/2022-03-12-active-admin-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:

1. Create a **Template** model (that we will populate in the database from a CSV file).
2. Create a page for our CSV upload.
3. Create a file for our CSV helper file.
4. Create a CSV file for our test upload.

```s
# 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:

```rb
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.

```csv
"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":

```rb
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:

1. Creating a page at the route `/admin/template`.
2. Adding a link to the page at the top of the page for uploading a CSV that will redirect to `admin/template/upload_csv`.
3. The route `admin/template/upload_csv` will render the `app/views/admin/csv/upload_csv.html.erb` view (that we will create next).
4. 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:

```html
<%= 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:

```rb
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](https://cdn.dennisokeeffe.com/assets/2022-04-05-uploading-files-in-active-admin/1-template-upload.webp)

The following page will display the form for your CSV file upload.

![Template form for the file upload](https://cdn.dennisokeeffe.com/assets/2022-04-05-uploading-files-in-active-admin/2-template-upload-form.webp)

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](https://cdn.dennisokeeffe.com/assets/2022-04-05-uploading-files-in-active-admin/3-success.webp)

If you have an issue, you will see the error message:

![Error](https://cdn.dennisokeeffe.com/assets/2022-04-05-uploading-files-in-active-admin/4-failure.webp)

## Summary

Today's post demonstrated how to upload a file to ActiveAdmin and process that upload.

## Resources and further reading

- [ActiveAdmin](https://activeadmin.info/)
- ["ActiveAdmin With Ruby On Rails 7"](https://blog.dennisokeeffe.com/blog/2022-03-12-active-admin-with-ruby-on-rails-7)
- [Source code](https://github.com/okeeffed/demo-upload-csv-to-active-admin)

_Photo credit: [`bernardhermant`](https://unsplash.com/@bernardhermant)_
