需求:后台可以汇出报名资料
有时候后台功能做再多,也不如 Microsoft Excel 或 Apple Numbers 试算表软件提供的分析功能,这时候如果有汇出功能,就可以很方便地把资料汇出来,用软件来打开浏览。
CSV 逗号分隔值(Comma-separated-values)是一种简单的资料格式,其文件以纯文本形式存储表格数据(数字和文本)。一行一笔资料,不同字段用逗号隔开。
例子:
app/views/admin/event_registrations/index.html.erb
<p>
<%= link_to "汇出 CSV", admin_event_registrations_path(:format => :csv) %>
</p>
app/controllers/admin/event_registrations_controller.rb
+ require ‘csv‘
class Admin::EventRegistrationsController < AdminController
def index
# (略)
+ respond_to do |format|
+ format.html
+ format.csv {
+ @registrations = @registrations.reorder("id ASC")
+ csv_string = CSV.generate do |csv|
+ csv << ["报名ID", "票种", "姓名", "状态", "Email", "报名时间"]
+ @registrations.each do |r|
+ csv << [r.id, r.ticket.name, r.name, t(r.status, :scope => "registration.status"), r.email, r.created_at]
+ end
+ end
+ send_data csv_string, :filename => "#{@event.friendly_id}-registrations-#{Time.now.to_s(:number)}.csv"
+ }
+ end
end
CSV 是 Ruby 内建的库,这里第一行需要先 require
它。使用 CSV.generate
可以产生出 csv_string
字符串,也就是要输出的 CSV 资料,接着透过 send_data
传给浏览器进行档案下载。
Time.now.to_s(:number)生成"20180811174126", to_s是简写:to_formatted_s(format=:default)
time = Time.now # => 2007-01-18 06:10:17 -06:00
time.to_formatted_s(:time) # => "06:10"
time.to_s(:time) # => "06:10"
time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
time.to_formatted_s(:number) # => "20070118061017"
time.to_formatted_s(:short) # => "18 Jan 06:10"
send_data(data, options={})
Axlsx-Rails — Spreadsheet templates for Rails(470??)
CSV 有个缺点,就是用 Microsoft Excel 打开时默认会变成乱码。这是因为汇出的 CSV 的字串编码是 UTF-8,但是 Excel 默认会用本地编码,例如中国大陆地区用 GB 2312
解决办法有二:
方法一: 以记事本开启后储存,再以 Excel 开启即可正常显示。
方法二: 开启 Excel 软件,新增空白活页簿(Workbook),然后在上方功能选项中点选「资料(Data)」->「取得外部资料 Get External Data」->「从文字档 From Text File...」→「选择汇出的 CSV 档案」→ 选择符号分隔(Delimited)、选择 File origin 编码是 Unicode (UTF-8) → 选择分隔符号是 Comma 逗点,即可正常显示。
如果上述 Excel 打开 CSV 档案的解法没办法接受的话,那只好想办法汇出 Excel 专用的 xlsx 格式了。这需要额外装 gem。
使用 axlsx_rails gem(470?)。
?? Rails 4.2, 5.0 or 5.1 (tested), 还不支持5.2
沿用上例子:安装3个gem后:
app/views/admin/event_registrations/index.html.erb
+ <%= link_to "汇出 Excel", admin_event_registrations_path(:format => :xlsx)
app/controllers/admin/event_registrations_controller.rb
在index中加上 format.xlsx
创建template:
app/views/admin/event_registrations/index.xlsx.axlsx
??:需要使用action_name.xlsx.axlsx格式作为名字。
wb = xlsx_package.workbook
wb.add_worksheet(name: "Buttons") do |sheet|
sheet.add_row ["报名ID", "票种", "姓名", "状态", "Email", "报名时间"]
@registrations.each do |r|
sheet.add_row [r.id, r.ticket.name, r.name, t(r.status, :scope => "registration.status"), r.email, r.created_at]
end
end