I have a Rails 6 controller function that generates a Excel file. This is a GET request/form submit of 3 criteria, 2 dates and a mode variable. Nothing fancy at all. This works with small amounts of data in the returned Excel file, but when larger volumes are required it takes ages and the browser times out. I've modified this, client side, with jQuery to override the timeout and submit the serialized form as a GET request in order to grab the search criteria used. The search, generation of the Excel file and response seems OK. Its the resulting document that appears corrupt when using the ajax mechanism below.
Of course I originally had issues with saving the file as its an ajax request but found a few references that showed a trick to use window.URL.createObjectURL()
along with an anchor and automated click to get around this. However, the resulting file is not what was originally generated and sent.
Server side controller function
This uses the gem axlsx to generate the Excel file
def download
@download_without_times = true
set_time_range_and_get_data(params[:mode])
render "bulk_download"
end
Even using send_file(@filename, options = {})
works if I call it directly but the same issue exists when saving via the ajax/createObjectURL method.
Server side view contents
I would suggest this is irrelevant but just in case
wb = xlsx_package.workbook
wb.add_worksheet(name: "Sensor Data") do |sheet_sensor_data|
sheet_sensor_data.add_row [
"datahog_id",
"sensor_data_id",
"collected_at",
"inserted_at",
"datahog_name",
"sensor_description",
"sensor_type",
"sensor_units",
"value",
"datahog_raw"
]
if !@sensor_data.blank?
@sensor_data.each do | sensor_data |
sheet_sensor_data.add_row [
sensor_data.datahog_sensor.datahog_id,
sensor_data.datahog_sensor_id,
sensor_data.datahog_timestamp.strftime(DATETIME),
sensor_data.created_at.strftime(DATETIME),
sensor_data.datahog_sensor.datahog.name,
sensor_data.datahog_sensor.display_label,
sensor_data.datahog_sensor.sensor_type,
sensor_data.datahog_sensor.display_units,
sensor_data.value,
sensor_data.datahog_raw
]
end
end
end
Client side Ajax function
Submits the serialized form and on success tries to save the returned 'data' as a file. Its just that he file appears to have been turned into garbage. So, I'm missing some kind of conversion or something.
$.ajax({
url:'/download_table_data.xlsx',
timeout: 0,
type:'GET',
responseType: "blob",
data:$(this).serialize(),
success:function(data, textStatus, jqXHR ){
// How you download a file by ajax
var fileName = 'download_table_data.xlsx';
const objectURL = window.URL.createObjectURL(new Blob([data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}))
var link= document.createElement('a');
link.href=objectURL;
link.download=fileName;
link.click();
},
error: function (xhr, status) {
toastr.error("Error getting data: " + xhr.responseText);
$('#download_data_form').show();
},
complete: function (xhr, status) {
intervals.push(setInterval(get_live_table_data, refresh_timer));
$('#notify_of_activity').hide();
$('#download_data_form').show();
}
});
If I use a Hex viewer to compare the working version with the garbage the browser is saving, its obvious there's an issue as follows:-
NOTE: Loads of EF BF BD which, I think, is the UTF-8 sequence of bytes for U+FFFD, which is the Unicode code point replacement character. Someone with a very similar issue was told he was probably decoding and encoding and introducing the issue. If I am, then I'm not sure where or how to fix it.
Request and response headers
If anyone can point me in the right direction it would be most appreciated.