I am working on a code base where I need to allow the user to download a PDF document that already resides on AWS S3. I have implemented a download concern that was used for a previous feature.
For this feature, I need to update the UI (A progress stepper) after the user has completed the file download. I was initially thinking that this would be as simple as:
- User clicks download
- API call is made where the file is downloaded using
send_data
. In this API call, I'd also update theFoo
model to change state to indicate that the user has downloaded the file; - Execute a
redirect_to request.referer
to reload the data. The changed state inFoo
will be responsible for showing the updated progress in the UI;
I was mistakenly thinking that this was going to be simple. The reasons for complexity:
send_data
is already rendering data, so I can't refresh the page usingredirect_to
as this triggers a multiple render error;send_data
does not work with theremote: true
option, so requesting data via an AJAX link and updating the ERB template is out;- I can write everything into a JS
on click
function, but this seems like a bit of a hack. I probably need to retrieve the file directly from AWS and skip my api? I'm suspecting that I might run into CORS issues as I don't have control over the server.
This is what my rails download method looks like currently:
def download
attachment = Attachment.find_by_id(params[:attachment_id])
content = send_data(
attachment.file.read,
filename: "#{attachment.title}.#{attachment.file.file.extension}",
type: attachment.content_type,
disposition: "attachment",
)
end
Th js code that basically worked looks like this where all the relevant paths & filenames are passed on to the JS via data-attributes:
$(document).on("click", "#download", function(e){
e.preventDefault();
const data = $('#temp-information').data();
var req = new XMLHttpRequest();
req.open("GET", data.path, true);
req.responseType = "blob";
const filename = data.title;
req.onload = function (event) {
var blob = req.response;
console.log(blob.size);
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download= filename;
document.body.appendChild(link);
link.click();
};
if (typeof window.navigator.msSaveBlob !== 'undefined') {
// Fix to work in IE11
window.navigator.msSaveBlob(blob, filename);
} else {
req.send();
}
});
What is the most effective & rails'y way of handling a file download & updating the UI after the download has been completed?