Не совсем ясно, чего вы пытаетесь достичь. Если вы пытаетесь позволить пользователю видеть ход загрузки, я не уверен, что вам действительно нужно что-либо делать, кроме send_data
, и большинство браузеров начнут загружать файл, включая отображение индикатора выполнения.
Поскольку кажется, что вы хотите что-то сделать после завершения загрузки файла, это немного сложнее. В этой проблеме нет ничего специфичного для Rails, и подход, который вы использовали, выглядит довольно разумным для меня.
В этой теме SO вы найдете длительное обсуждение этой проблемы и различных способов, которыми люди пытались ее решить. В целом решения имеют одинаковую базовую структуру, которая заключается в простом опросе сервера.
В вашем Rails-приложении вы можете реализовать это примерно следующим образом. Предположим, вы добавили поле status
в модель вложения ...
def download
attachment = Attachment.find_by_id(params[:attachment_id])
attachment.update(status: "downloading")
send_data(
attachment.file.read,
filename: "#{attachment.title}.#{attachment.file.file.extension}",
type: attachment.content_type,
disposition: "attachment",
)
attachment.update(status: "complete")
end
Затем вы можете добавить конечную точку, которая возвращает статус файла. Таким образом, когда пользователь начинает скачивать файл, вы начинаете опрашивать эту конечную точку.
def attachment_status
attachment = Attachment.find_by_id(params[:attachment_id])
respond_to do |format|
format.json do
{status: attachment.status}
end
end
end
Затем в Javascript, например, используя HttpPromise :
var http = new HttpPromise;
function poll(doneFn) {
http.get("/status.json") // you will need to set your actual status endpoint path here
.success(function(data,xhr){
if (data.status == "complete") {
doneFn();
}
});
};
function downloadFinished(){
// ... do whatever you want on finish here ...
};
setInterval(function(){ poll(downloadFinished) }, 5000);
Это не самая красивая вещь в мире, но она должна выполнить свою работу.
Удачи!