导出csv文件,导出axlsx文件。gem 'Axlsx-Rails' (470);导入csv文件。
汇出 CSV 档案
需求:后台可以汇出报名资料
有时候后台功能做再多,也不如 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 < AdminControllerdef 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" + } + endend
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:00time.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?)
安装看git
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
导入 CSV 档案 (Rake直接导入)
假设我们拿到这样的 CSV 档案,接下来要如果汇入数据库呢?总不能一笔一笔输入太慢了,当然要用写程序的方式来做汇入。
如果汇入是程序员的一次性的任务,我们可以不需要实作 Web UI,只需要一个 rake 任务可以执行就好了。
编辑 lib/tasks/dev.rake
,让我们新增一个 import_registration_csv_file
任务
lib/tasks/dev.rake
+ require 'csv'namespace :dev do+ task :import_registration_csv_file => :environment do + event = Event.find_by_friendly_id("fullstack-meetup") + tickets = event.tickets + + success = 0 + failed_records = [] + + CSV.foreach("#{Rails.root}/tmp/registrations.csv") do |row| + registration = event.registrations.new( :status => "confirmed", + :ticket => tickets.find{ |t| t.name == row[0] }, + :name => row[1], + :email => row[2], + :cellphone => row[3], + :website => row[4], + :bio => row[5], + :created_at => Time.parse(row[6]) ) + + if registration.save + success += 1 + else + failed_records << [row, registration] + end + end + + puts "总共汇入 #{success} 笔,失败 #{failed_records.size} 笔" + + failed_records.each do |record| + puts "#{record[0]} ---> #{record[1].errors.full_messages}" + end + + end
执行 rake dev:import_registration_csv_file
就会执行了汇入的操作到 fullstack-meetup
这个活动
解说:
- 和汇出 CSV 一样,Ruby 内建了 CSV 库可以解析 CSV,所以第一行先
require 'csv'
CSV.foreach
会打开这个 CSV 档案跑循环,每笔资料就是一行row
,那一行的第一列是row[0]
、第二列是row[1]
。只要依序塞给event.registrations.new
即可。- CSV 中的票种是string,但是转进我们的数据库中需要转换成 Ticket model,因此这里写成
tickets.find{ |t| t.name == row[0] }
用票种名称去找是哪一个对象。 - 时间也是一样,透过
Time.parse
把string转成时间对象 - 因为汇入会一次汇入非常多笔,我们希望不管每笔资料 save 成功或失败,都能跑完全部资料,最后印出一个总结:告诉我们总共几笔成功,总共几笔失败,是哪些笔失败又是什么原因。
把汇入档案存下来纪录过程
如果这是一个面向终端用户的功能,会需要实作的更完整,例如:
- 把上传的档案先存下来,先给用户预览字段顺序是否正确、有多少数据要汇入、哪些数据有问题
- 确认后,才开始汇入数据库
- 可以浏览过往的汇入历史纪录
执行 rails g model registration_import
,这个 Model 会存下上传的 CSV 档案,并记录汇入的结果。
编辑 db/migrate/2017XXXXXX4512_create_registration_imports.rb
db/migrate/2017XXXXXX4512_create_registration_imports.rb
class CreateRegistrationImports < ActiveRecord::Migration[5.0]def changecreate_table :registration_imports do |t| + t.string :status + t.string :csv_file + t.integer :event_id, :index => true + t.integer :user_id + t.integer :total_count + t.integer :success_count + t.text :error_messagest.timestampsendendend
执行 rake db:migrate
执行 rails g uploader registration_import_csv
编辑 app/models/registration_import.rb
,其中的 process!
方法就是要执行的汇入操作。
app/models/registration_import.rb
+ require 'csv'class RegistrationImport < ApplicationRecord+ mount_uploader :csv_file, RegistrationImportCsvUploader + + validates_presence_of :csv_file + + belongs_to :event + belongs_to :user + + serialize :error_messages, JSON + + def process! + csv_string = self.csv_file.read.force_encoding('utf-8') + tickets = self.event.tickets + + success = 0 + failed_records = [] + + CSV.parse(csv_string) do |row| + registration = self.event.registrations.new( :status => "confirmed", + :ticket => tickets.find{ |t| t.name == row[0] }, + :name => row[1], + :email => row[2], + :cellphone => row[3], + :website => row[4], + :bio => row[5], + :created_at => Time.parse(row[6]) ) + + if registration.save + success += 1 + else + failed_records << [row, registration.errors.full_messages] + end + end + + self.status = "imported" + self.success_count = success + self.total_count = success + failed_records.size + self.error_messages = failed_records + + self.save! + end end
编辑 app/models/event.rb
app/models/event.rb
has_many :registrations, :dependent => :destroy + has_many :registration_imports, :dependent => :destroy
编辑 config/routes.rb
config/routes.rb
namespace :admin do# (略)resources :events do + resources :registration_imports
编辑 app/views/admin/event_registrations/index.html.erb
加上一个按钮
app/views/admin/event_registrations/index.html.erb
<p class="text-right"><%= link_to "New Registration", new_admin_event_registration_path(@event), :class => "btn btn-primary" %> + <%= link_to "Import Registration", admin_event_registration_imports_path(@event), :class => "btn btn-primary" %></p>
执行 rails g controller admin::registration_imports
编辑 app/controllers/admin/registration_imports_controller.rb
app/controllers/admin/registration_imports_controller.rb
- class Admin::RegistrationImportsController < ApplicationController + class Admin::RegistrationImportsController < AdminController+ before_action :require_editor! + before_action :find_event + + def index + @imports = @event.registration_imports.order("id DESC") + end + + def create + @import = @event.registration_imports.new(registration_import_params) + @import.status = "pending" + @import.user = current_user + + if @import.save + @import.process! + flash[:notice] = "汇入完成" + end + + redirect_to admin_event_registration_imports_path(@event) + end + + protected + + def find_event + @event = Event.find_by_friendly_id!(params[:event_id]) + end + + def registration_import_params + params.require(:registration_import).permit(:csv_file) + endend
在 @import.save
之后,随即呼叫 process!
开始汇入。
另外,⚠️:这里的用户需求第1步和第2步这里并没有实现。
如果要实现的话,标红的4行代码,去掉@import.process!
把process方法单独放入一个controller#action中,并在index.html.erb中添加一个确认的button
在点击button后才会汇入数据到数据库中。
(或者,新增一个Model,数据临时存入这个model层,然后预览一下,该删除的删除,该保留的保留
然后再,存入真正储存数据的Model。)
新增 app/views/admin/registration_imports/index.html.erb
显示档案上传的输入框,以及历史汇入纪录。
app/views/admin/registration_imports/index.html.erb
<h1><%= @event.name %> / Registrations Import</h1> <%= form_for [:admin, @event, RegistrationImport.new] do |f| %> <div class="form-group"> <%= f.label :csv_file %> <%= f.file_field :csv_file, :required => true, :class => "form-control" %> </div> <div class="form-group"> <%= f.submit "送出", :class => "btn btn-primary" %> </div> <% end %> <table class="table"> <tr> <th>ID</th> <th>状态</th> <th>CSV档案</th> <th>总笔数</th> <th>汇入成功笔数</th> <th>错误讯息</th> </tr> <% @imports.each do |import| %> <tr> <td><%= import.id %></td> <td><%= import.status %></td> <td><%= link_to import.csv_file.url, import.csv_file.url %></td> <td><%= import.total_count %></td> <td><%= import.success_count %></td> <td> <ul> <% Array(import.error_messages).each do |e| %> <li><%= e[0] %> ----> <strong><%= e[1] %></strong></li> <% end %> </ul> </td> </tr> <% end %> </table>
这样就完工啦。
转载于:https://www.cnblogs.com/chentianwei/p/9460616.html
导出csv文件,导出axlsx文件。gem 'Axlsx-Rails' (470);导入csv文件。相关推荐
- Android修改R文件包名程,以及批量修改导入R文件
当我们创建Android工程时,R文件所在包名即初始创建的包名,当我们后期想修改R文件的包名时,其实只需要在 AndroidManifest.xml中将package的名字修改了保存即可, 或者通过 ...
- mysql的indata文件_【数据分析】MySQL之不能导入本地文件“Loading local data is disable;”...
今天在使用"利用MySQL的命令行进行CSV文件的导入"时,遇到了这样一个问题: 提示本地文件无法导入,必须要"同时获得客户端和服务器端的许可". 很难受,于是 ...
- thinkphh5导入php文件,Thinkphp5.0如何导入导出
ThinkPHP是一个免费开源的,快速.简单的面向对象的轻量级PHP 开发框架,遵循 Apache2 开源协议发布,是为了简化企业级应用开发和敏捷WEB应用开发而诞生的.本篇文章我们主要跟大家分享Th ...
- MySQL导入csv文件内容到Table及数据库的自增主键设置
写在前面 目的是测试将csv文件内容导入到表中, 同时记录一下自增主键的设置. 测试采用MySQL8.0. 新建表customer_info如下, 未设置主键. 修改上表, 添加主键id, 并设置为自 ...
- mysql linux导入csv主键,MySQL导入csv文件内容到Table及数据库的自增主键设置
写在前面 目的是测试将csv文件内容导入到表中, 同时记录一下自增主键的设置. 测试采用MySQL8.0. 新建表customer_info如下, 未设置主键. 修改上表, 添加主键id, 并设置为自 ...
- 关于使用Java后台导入excel文件,读取数据后,更新数据库,并返回数据给到前端的相关问题总结
在之前的项目中,使用到了Java后台读取excel文件数据的功能点,本想着该功能点已经做过了,这一类的应该都大差不离,不过在刚结束的一个项目中,现实给我深深的上了一课,特此编写此片博客,以作记录,并给 ...
- Linux下导入SQL文件及MySQL常用命令
Linux系统下可以直接复制SQL语句进行导入,但是这个方法容易出现导入失败的现象,我们可以直接导入sql文件,可以大大提高成功率. 在导入sql文件前,先说一下MySQL的常用命令. MySQL的登 ...
- mysql命令行导入dmp文件_cmd 命令行 imp导入dmp oracle数据库
简介: 开发者在开发过程中使用到Oracle数据库时,总是避免不了要还原数据库.通常Oracle导出的备份数据库文件为dmp文件.本篇介绍了下怎么导入dmp文件到对应的Oracle数据库中. 步骤一 ...
- 如何导入asl文件?ps制作知识
asl文件是Photoshop里的图层样式文件!一个图层包里可以有很多个图层样式! -fuSCj T j9;". 如何导入asl文件? 6c>t|=Ss( FiJJe ...
- Perl导入代码文件
从函数复用开始:eval和do执行perl文件 当我们定义了一个功能比较通用的子程序,比如获取数值的绝对值.想要到处使用这个子程序,就得不断复制.粘贴这段绝对值函数的定义文本.显然,这是不太理想的方式 ...
最新文章
- api.533.net 文章迁移计划
- C语言 实现一个函数判断year是不是润年
- k8s部署nacos集群:3个pod、连接外部mysql读写分离集群
- java程序员面试中的5个杀手锏问题
- uwp连接mysql数据库_在 UWP 应用中使用 SQLite 数据库
- mvc json 乱码_你了解JSON吗?——Jackson、FastJson在SpringMVC中的简单使用
- java cxf服务端_webservice概述及cxf在Java开发中应用(二) 简单搭建cxf服务端
- mysql 免安装 自启动_MYSQL在Win下免安装zip
- Oracle的expdp导出、impdp导出命令
- 顶会两篇论文连发,华为云医疗AI低调中崭露头角
- 网络安全渗透测试自学
- iTunes降级操作
- 卫星控制类操作系统VAX/VMS简介
- 索尼Z2(L50t)刷CM12教程
- 机器学习中的置信区间与置信度
- Android开发: 美化输入框EditText
- 结构体对齐和补齐(详细解释)
- 合格资本工具_《商业银行资本管理办法附件》附件1——资本工具合格标准.doc...
- 掌财社:津投期货新股为什么容易出现天地板?
- vue3实现活跃度(热力图)
热门文章
- Hibernate多列作为联合主键(六)
- 【渝粤教育】国家开放大学2018年秋季 0727-22T思想道德修养与法律基础 参考试题
- [渝粤教育] 中国地质大学 高层建筑施工 复习题 (2)
- [渝粤教育] 西南科技大学 管理信息系统 在线考试复习资料(2)
- 软件类配置(六)【ubuntu16.04安装opencv3.4.1】
- 车道线检测-python实现
- 梯度下降来龙去脉附matlab代码
- 那些聪明人都是怎么提高情商的?
- NOIP2018初赛 解题报告
- POJ1064 Cable master 【二分找最大值】