Сложность с send_data в Ruby on Rails в сочетании с плагином Spreadsheet
У меня есть функция в контроллере, которая принимает некоторые спецификации и генерирует отчет по ним. Эта функция user_report вызывается в представлении:
<% = submit_to_remote "кнопка отправки", "Экспорт отчета в Excel",: url => {:controller =>:reports,:action =>:user_report,:print_state => 'print'} % >
В reports_controller я использую плагин Spreadsheet для генерации файла Excel в функции user_report. Я хочу использовать send_data для потоковой передачи файла пользователю без предварительного его создания на сервере. Исследование, которое я провел, показывает, что использование StringIO - это путь, как показано ниже. К сожалению, ничего не происходит, когда я вызываю send_data. Плагин, кажется, хорошо работает, создавая файл и сохраняя его на сервере, но ничего не делает, когда я использую send_file, предполагая, что проблема не в плагине. Но тогда что я делаю не так с send_file/send_data?
Сама функция выглядит так:
def user_report
if request.post?
unless params[:reports][:userid].blank?
@userid=params[:reports][:userid]
end
if params[:print_state]=='print'
report = Spreadsheet::Workbook.new
info = report.create_worksheet :name => 'User Information'
info.row(1).push 'User ID', @userid
@outfile = "Report_for_#{@userid}.xls"
require 'stringio'
data = StringIO.new ''
report.write data
send_data data.string, :type=>"application/excel", :disposition=>'attachment', :filename => @outfile
end
respond_to do |format|
format.js { }
end
end
конец
Файл журнала читает 18.10.2010 14:13:59 ИНФОРМАЦИЯ - Отправка данных Report_for_jjohnson.xls, но загрузка не начинается в браузере. Я преуспел в использовании send_data в этом приложении раньше, что сбивает с толку.
Я использую Rails v2.3, Ruby v1.8.7 и Spreadsheet v6.4.1 на spreadsheet.rubyforge.org.
3 ответа
Просто измените строку:
send_data data.string, :type=>"application/excel", :disposition=>'attachment', :filename => @outfile
чтобы:
send_data data.string.bytes.to_a.pack("C*"), :type=>"application/excel", :disposition=>'attachment', :filename => @outfile
Для тех, кто смотрит на это в (или после) 2022 году, возможным решением этого будет использование Axlsx Gem. Интерфейс предоставляет метод для преобразования его в объект StringIO. (Из документации Axlsx )
#serialize to a file
p = Axlsx::Package.new
# ......add cool stuff to your workbook......
# Serialize to a stream
s = p.to_stream()
send_data(
s.read,
:type => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
:disposition => 'attachment',
:filename => @filename
)
Хотя я не люблю писать и удалять, но с таблицей кажется единственным решением.
# write the file
book.write "Employee_History_#{ params[:id]}.xls"
# send the file
send_file "Employee_History_#{ params[:id]}.xls", :type => "application/vnd.ms-excel", :filename => "data.xls", :stream => false
# and then delete the file
File.delete("Employee_History_#{ params[:id]}.xls")