The main table in my backend gets populated by a CSV file. When seeding and running rails db:seed
, the CSV files in lib/assets/csv
is read with file = File.read(Rails.root.join('lib', 'assets', 'csv', 'data.csv')
, and the logic in seeds.rb
runs through each row to create a table entry, populating the fields with the CSV column data.
I've also implemented Thoughtbot's Administrate for a UI admin dashboard to view this data.
So my question is, what is the best way to configure some kind of custom file upload system on Administrate dashboard if I ever need to replace the files sitting in lib/assets/csv
and reseed?
I've looked at ActiveStorage but I've only ever used it to store files like an image specifically related to a table entry, not for seeding the entire table.
Yes, it is possible, and you don't need ActiveStorage. Rails's basic file upload facilities will be enough. Meanwhile, Administrate tries to follow Rails conventions, and provides hooks for you to alter the templates and refer to your own controllers and actions where you can implement this. Here's an example of how you could solve your problem.
First, you'll want to add a form with a file field. Admins will be able to use it to upload CSVs.
There are many places where you could put this form. For this example, let's say that it's "products" that you want to import (model
Product
), and you want to put the link in the index page.You can override Administrate's own templates with your own ones. The following command will generate a copy of the
index
template that you can customize and Administrate will use instead of its own:This will get you a new file
app/views/admin/application/index.html.erb
.Alter it to add a link to a separate page that will host the upload form:
You can put this in between the page title and the search bar. Or wherever you want, really. It does the following:
if
checks that we are in the index page for "products" and not for something else.link_to
links to a page that we haven't created yet, which will host the upload form.If you load the products index page now, it will show an error
NameError
, with messageundefined local variable or method 'upload_admin_products_path'
. This is because we still don't have a route for this new page of ours. Lets add it now.In the routes file
config/routes.rb
, you'll already have a routeresources :products
. Change it to look like this:This actually adds two routes, not one. One will be for the form page, while the other one will be for the action that will process the uploaded CSV.
For now, you can click on the link and go to the new page. It will break again. This time the error will be
Unknown action - The action 'upload_form' could not be found for Admin::ProductsController
. That's because we haven't provided a view for this page yet. Let's do it now.Add a view with the following contents at
app/views/admin/products/upload_form.html.erb
:Now you should be able to load the page and see the form. I have added additional markup (like those
header
andsection
elements) to make it look similar to other pages that Administrate provides.That form has a
file_field
and a submit button. On submit, it will send the file to the current URL (/admin/products/upload
) as a POST request. It will be handled by thepost
route we added earlier, on the actionupload_process
. Let's write that now.On the controller
Admin::ProductsController
, add the following method to implement the action:This will create new products based on what's contained in the CSV, and then will redirect the user back to the products index page.
This example action is very simple and may not suit your needs exactly. You probably want to copy your code from
seeds.rb
and paste it in between myStart
andEnd
comments, so that it does what you want exactly. There are many possibilities.