Rails 重用页面的表格做 CSV 导出

lingceng · 2015年12月23日 · 最后由 torvaldsdb 回复于 2016年12月22日 · 3381 次阅读

rails 做 csv 导出挺容易的,只是大部分还是要组装二维数组。 我想直接抓取页面的表格做导出,这样页面显示时的一些转换也可以重用了。

代码如下:

def generate_csv_data(template = nil)
  template ||= "#{controller_name}/#{action_name}.html.slim"
  content = render_to_string(template)
  doc =  Nokogiri::HTML(content)

  table =  doc.at_css('table')
  data = table.css('tr').map do |r|
    r.css('td,th').map(&:text).to_csv
  end.join

  # Convert from utf8 to gbk to make it compatible with Windows Office Excel
  # And Mac number can work with GBK too
  data = data.encode('GBK', undef: :replace, replace: "")
end

全文在这里 http://lingceng.github.io/blog/2015/12/23/export-csv-or-excel-by-re-using-existing-html-view/

我现在的做法是写一个纯 csv 导出,然后用d3.csv,画出表格,正好和你方向相反。。。

class CcbReviewsController < ApplicationController
  def index
    @q = CcbReview.includes(:change_owner).search(params[:q])
    @ccb_reviews = @q.result.paginate(page: params[:page], per_page: 10)

    respond_to do |format|
      format.html
      format.json
      format.csv do
        render_csv_header :wip.to_s
        csv_res = CSV.generate do |csv|
          csv << ['CCB Number', 'State', 'Title', 'Description', 'Reason', 'Purpose']
          CcbReview.all.find_each do |ccb_review|
            values = []
            values << ccb_review.ccb_number
            values << ccb_review.state
            values << ccb_review.title
            values << ccb_review.description
            values << ccb_review.reason
            values << ccb_review.purpose
            csv << values
          end
        end
        send_data "\xEF\xBB\xBF" << csv_res
      end
    end
  end

private

  def render_csv_header(filename = nil)
    filename ||= params[:action]
    filename += '.csv'

    if request.env['HTTP_USER_AGENT'] =~ /msie/i
      headers['Pragma'] = 'public'
      headers['Content-type'] = 'text/plain'
      headers['Cache-Control'] = 'no-cache, must-revalidate, post-check=0, pre-check=0'
      headers['Content-Disposition'] = "attachment; filename=\"#{filename}\""
      headers['Expires'] = '0'
    else
      headers['Content-Type'] ||= 'text/csv'
      headers['Content-Disposition'] = "attachment; filename=\"#{filename}\""
    end
  end
end

如果是浏览器载完页面再导出,是否可以考虑用 JS 来做。

#2 楼 @adamshen 之前做过用 js 抓取页面导出 csv(那时候还是用 java 😄),逻辑几乎一样,因为都是用 css 选择元素。

只是要考虑两点:

  1. 浏览器兼容性,IE 可能不支持
  2. 只能导出当前页的内容

而用后端导出的方式,调整下每页的条数就可以导出更多,见https://gist.github.com/lingceng/840f97f17128d8a9fd3b

我刚好看到这里,刚好遇见你。

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