Rails项目替换to_xls gem生成xlsx文件的方案咨询
从to_xls切换到xlsx格式生成方案
一、to_xls能否直接生成xlsx?
不行。to_xls依赖的spreadsheet库仅支持旧版的.xls格式(BIFF8标准),完全不支持基于OpenXML的.xlsx格式,必须更换gem实现需求。
二、推荐的xlsx生成gem
- axlsx:功能完整、文档完善的xlsx生成库,支持样式、多sheet、公式等特性,是Rails项目中生成xlsx的主流选择。
- roo:主要定位是读取各类电子表格格式,生成xlsx的能力有限,不推荐用于生成场景。
- 额外可选:
axlsx_rails,是axlsx针对Rails的封装,可进一步简化响应处理逻辑。
三、代码修改指导
基于你的现有代码,改用axlsx重写核心逻辑:
首先在Gemfile中添加依赖:
gem 'axlsx'
执行bundle install完成安装。
然后修改响应器代码:
class ToXmlResponder < Dossier::Responder def to_xlsx set_content_disposition! controller.response_body = to_xlsx_raw end def to_xlsx_raw Axlsx::Package.new do |p| # 写入内容工作表 add_content_sheet(p.workbook) # 写入元数据工作表 add_metadata_sheet(p.workbook) response = StringIO.new p.serialize(response) response.string.force_encoding('binary') end end def add_content_sheet(workbook) xls_opts = collection_and_headers(resource.raw_results.arrays) headers = xls_opts[1] items = resource.results.hashes columns = resource.raw_results.headers workbook.add_worksheet(name: '内容') do |sheet| # 写入表头 sheet.add_row headers # 逐行写入数据 items.each do |item| sheet.add_row columns.map { |col| item[col] } end end end def add_metadata_sheet(workbook) metadata = [ { name: I18n.t('report_info.start_date'), value: resource.start_date_in_timezone(resource.user_time_zone).to_s }, { name: I18n.t('report_info.end_date'), value: resource.end_date_in_timezone(resource.user_time_zone).to_s }, { name: I18n.t('report_info.export_by'), value: resource.user.username.to_s }, { name: I18n.t('report_info.export_date'), value: Time.now.in_time_zone(resource.user_time_zone).to_s } ].reject { |r| r[:value].empty? } workbook.add_worksheet(name: I18n.t('report_info.sheet_name')) do |sheet| metadata.each do |row| sheet.add_row [row[:name], row[:value]] end end end private def set_content_disposition! filename = "report_#{Time.now.strftime('%Y%m%d')}.xlsx" controller.response.headers['Content-Disposition'] = "attachment; filename=\"#{filename}\"" controller.response.headers['Content-Type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' end end
修改说明:
- 核心逻辑替换:用
Axlsx::Package替代原有的Spreadsheet::Workbook,这是axlsx的核心生成对象。 - 拆分工作表创建:将原有的
xls_content和xls_metadata拆分为独立的工作表创建方法,逻辑更清晰。 - 响应头更新:调整Content-Type为xlsx对应的MIME类型,同时修正文件名后缀。
- 简化数据处理:无需再用
Hashie::Mash包装数据,直接通过原始哈希取数即可。
四、额外注意事项
- 如果需要自定义样式(如表头加粗、日期格式设置),axlsx支持丰富的样式配置,可在
add_row时传入style参数实现。 - 处理大文件导出时,axlsx支持流式输出,可避免内存占用过高,具体可参考官方文档实现。
内容的提问来源于stack exchange,提问作者Dev V
相关产品推荐
相关产品推荐

