Rails 导出数据到 Excel 表格(同步/异步)形式

hiveer · 2020年08月09日 · 最后由 xiaxia 回复于 2021年05月25日 · 2404 次阅读

准备

# For dealing with exel
gem 'caxlsx'
gem 'caxlsx_rails'

参考: https://github.com/caxlsx/caxlsx_rails

Axlsx-Rails 提供了一个 renderer 和一个 template handler. 它添加了一个新的 format :xlsx,并且可以解析 .xlsx.axlsx 模版。

同步形式

在控制器层,可以处理 :xlsx format 的请求:

class ButtonController < ApplicationController
  def action_name
    @buttons = Button.all
    respond_to do |format|
      format.xlsx
    end
  end
end

然后我们需要提供一个模版,根据 convention,它的名字需要是这样: action_name.xlsx.axlsx

wb = xlsx_package.workbook
wb.add_worksheet(name: "Buttons") do |sheet|
  @buttons.each do |button|
    sheet.add_row [button.name, button.category, button.price]
  end
end

然后我们就可以通过请求,直接下载 excel 文件

异步形式

前端 Ajax call

$(".export-consumers").on('click', (e) =>{
  e.preventDefault();
  $.ajax({
    method: 'GET',
    dataType: 'json',
    url: `/admin/consumers.js?campaign_id=${e.currentTarget.dataset.campaignId}`
  }).done((response) => {
    window.location = `/admin/consumers/download-consumers?file_name=${response.exported_file_name}`;
  }).fail((msg) => {
    alert('Export Failed');
  })
});

后端生成临时文件

respond_to do |format|
  format.js do
    @consumers = consumers
    exported_file_name = Admin::XlsxGeneration.new(@consumers, @current_campaign_id).build_tw_consumers_xlsx
    render json: {exported_file_name: exported_file_name}
  end
end

后端提供文件下载接口

def download_consumers
  send_file Rails.root.join("tmp", "#{params[:file_name]}.xlsx"), type: :xlsx, filename: "#{params[:file_name]}.xlsx"
end

对于异步形式的下载,上面示例的方案是先生成临时文件,返回文件名,然后再异步的下载这个文件。这个方案经过验证,有效可行。

对于异步的情况我还有一个想法,就是在后端不生成文件,直接通过send_data异步返回文件,但是我没有成功,因为在前端的 callback( done ) 中,没法拿到send_data返回的文件数据。不知道有人尝试过没?

试试 send_file?

后端生成临时文件

如果多台机器部署会有问题

我一般直接仍 aliyun oss 上

lidashuang 回复

哈哈,是的,谢谢指出这个潜在的问题。 这个简单的方案不适合多台服务器的情况。

请问如何将导出来的 excel 数据居左

需要 登录 后方可回复, 如果你还没有账号请 注册新账号