Exporting CSV, Excel and Docx
Bài đăng này đã không được cập nhật trong 9 năm
I. Exporting to CSV
Giả sử cần xuất dữ liệu cho đối tượng là "product". Không cần sử dụng bất kỳ gem nào cũng có thể dễ dàng export dữ liệu ra 1 file csv. Sử dụng thư viện CSV library để sinh ra dữ liệu CSV. Điều đơn giản cần làm là thêm dòng lệnh sau vào file config của app :
require File.expand_path("../boot", __FILE__)
require "csv"
Dữ liệu (comma-separated data
) sẽ được sinh ra khi user vào /products.csv path
. Để export được, trong controller của đối tương mà muốn xuất dữ liệu (/app/controllers/products_controller.rb
) thêm 1 khối respond_to
block. Ví dụ như đoạn mã sau :
class ProductsController < ApplicationController
def index
@products = Product.order(:name)
respond_to do |format|
format.html
format.csv {render text: @products.to_csv}
end
end
end
Trong model của đối tượng thêm đoạn code sau để sinh ra dữ liệu (CSV data
) :
def self.to_csv
CSV.generate do |csv|
csv << column_names
all.each do |product|
csv << product.attributes.values_at(*column_names)
end
end
end
Ở đây dữ liệu được sinh ra nhờ vào method to_csv
là method kết hợp giữa method to_json
và to_xml
. Nếu không muốn data sinh ra trong 1 dòng duy nhất thì có thể sử dụng send_data
thay vì render :text
trong controller. Khi load lại trang thì file CSV sẽ được download.
Nếu muốn chỉ download file CSV khi click vào link hoặc button thì có thể làm theo cách sau :
- Định nghĩa 1 method để lấy dữ liệu bên trong
model.rb
def download_keys keys
CSV.generate do |csv|
csv << column_names
keys.each do |key|
csv << product.attributes.values_at(*column_names)
end
end
end
- Trong controller viết 1 method để gọi đến khi click link:
def index
download_file params[:download] if params[:download]
end
private
def download_file download_option
filename = "product"
send_data Product.all.download_keys(keys),
type: "text/csv; charset=UTF-8; header=present",
disposition: "attachment; filename=#{filename}"
end
- Ở phần view (ví dụ
product/index.html.erb
) thêm đường link để gọi method download trong controller :
<%= link_to "download CSV", products_path, class: "btn btn-success" %>
II. Exporting to Excel
Step1
: thêm gem vaòGemfile
:
gem "axlsx", "2.0.0"
Step2
: Viết hàm download (có thể tạo file.rb
trongapp/model/concerns
), tham số truyền vào có thể là tên file mong muốn, ví dụ:
generate_excel_report file_name
Trong hàm, đầu tiên sẽ tạo 1 file trống bằng dòng lệnh sau:
package = Axlsx::Package.new
workbook = package.workbook
- Tạo
sheet
cho file : Trong 1 file có thể gồm nhiều sheet, để tạo sheet cho file dùng lệnh sau :
workbook.add_worksheet(name: "sheet_1") do |sheet|
...
end
- Trong vòng
do ... end
trên sẽ thêm các dòng lệnh cần để tạo nội dung cho sheet đó. Nếu muốn địnhstyle
chorow + colum
trong file excel thì sử dụng lệnhadd_style
, ví dụ như dòng lệnh sau :
color_title_table = workbook.styles.add_style(
bg_color: Settings.color.bg_title_row, b: true,
alignment: {horizontal: :left}, border: Axlsx::STYLE_THIN_BORDER)
bg_color
: màu nền mong muốn cho từng cell cụ thể
`b:true` -> in đậm
`u: single` -> có gạch chân
`alignment:`
`horizontal: :left`:căn lề trái/phải
`border: Axlsx::STYLE_THIN_BORDER` -> kiểu và kích cỡ của border...
- Ví dụ :
color_title_table = workbook.styles.add_style(bg_color: "F2DDDC", b: true, alignment: {horizontal: :left}, border: Axlsx::STYLE_THIN_BORDER)
- Để đặt tên cho file dùng câu lệnh sau :
workbook.add_worksheet(name: "product_excel") do |sheet|
/* Nội dung muốn in ra trong report */
end
- Thêm row trong file excel, dùng
sheet.add_row
, ví dụ như dòng lệnh sau :
sheet.add_row "new row", style: bold_text
Muốn row có bao nhiêu cell (số cột của bảng) thì tạo bằng ấy cell tương ứng, ví dụ như muốn tạo row_title
cho 1 bảng excel có 3 cột :
row_title = ["item1", "item2", "item3"]
add row_title trên vào bảng và định kiểu style cho nó, ta làm như sau :
sheet.add_row row_title, style: color_title_table, height: 50
Insert ảnh vào file excel:
def insert_img sheet, link_img, x, y, height, width
path_img = get_local_link_file link_img
if link_img.present? && File.exist?(path_img)
img = File.expand_path path_img, __FILE__
sheet.add_image image_src: img do |image|
image.width, image.height = width, height if width && height
image.start_at x, y
end
end
end
//sheet : sheet hiện tại cần chèn ảnh
//link_img : đường dẫn tới file ảnh
//x : tọa độ ngang, vị trí của ô cần chèn ảnh (int, tính từ 0)
//y : tọa độ dọc, vị trí của ô cần chèn ảnh (int, tính từ 0)
//height : chiều cao mong muốn cho ảnh (trung bình khoảng 50)
//width : độ rộng mong muốn cho ảnh (trung bình khoảng 40)
III. Exporting docx
Tương tự như xuất dữ liệu ra file excel
- Bước 1 : Thêm gem vao Gemfile
gem "docxtor"
- Bước 2 : viết 1 hàm xuất data
generate_word_report file_name
1 hàm cơ bản có thể viết như sau :
package = Docxtor.generate do
//tạo 1 file docx
table_of_contents "Contents"
h 1, "heading1"
p "text1", :b => true do
//1 paragraph
style 'p1'
spacing :before => 80, :after => 240
italic; u
w "text2"
br
write "text3"
end
h 2 do
w "heading2"
line_break
write "some text"
br
write "another text"
end
p "content", :style => 'p2', :i => true, :align => "center"
end
package.save("file_name.docx")
// save file với tên là tham số lúc truyền vào
Entry point
Docxtor.generate do
...
end
Paragraphs
- Phần chính trong bản word này là đoạn. Có thể xây dựng đoạn bằng các cách sau :
p "Hi there!", :bold => true
//Tương đương với
p do
w "Hi there!"
b
end
//OR
p do
write "Hi there!"
bold
end
- Style được viết chung trong khối block sẽ được apply trong cả đoạn, có nhiều cách khác nhau để định nghĩa
text
và cácoption
cho đoạn.
p "I'm a first string in this paragraph", :bold => true do
write "I'm a second one."
u
w "And we all will be bold and underlined in the same time!"
end
- Headings
h 1, "Chapter 1"
h 2, "Where our hero goes for an adventure"
-
Footers & Headers
Các thuộc tính cho footer và header :
Chỉ định trang mà footer + header xuất hiện :
:odd - trang lẻ
:even - trang chẵn
only :first - trang đầu tiên
Căn lề :
:center - giữa
:left - trái
:right - phải
Nội dung của footer/heade
r chứa từ khóa đặc biệt :pagenum
, index của trang được chèn nội dung.
footer :pagenum, :align => :center
header "Proudly made by me", :pages => :odd
footer "2013", :pages => :first, :align => :right
Breaks:
Sang trang mới : page_break
Xuống dòng : br
`Styles` : tương tự như trong excel.
`Nén file export` : `require zip` trong phần định nghĩa `export`method
require "zip/zip"
Hàm nén :
def export_zip_file filename, file_destination, zipfile_name
Zip::ZipFile.open(zipfile_name, Zip::ZipFile::CREATE) do |zipfile|
zipfile.add filename, file_destination
end
FileUtils.rm_f file_destination
end
Trong hàm xuất report, chèn method export_zip_file
trên vào để nén file (sau khi .save
). Ví dụ :
def report_word file_name
package = Docxtor.generate do
header ...
p title, b: true
........... //nội dung file export
package.save "#{file_name}.docx"
export_zip_file "#{title}.docx", "#{file_name}.docx", "#{file_name}.zip"
end
end
V. Nguồn tham khảo
1. https://github.com/docxtor/docxtor
2. http://ruby-doc.org/stdlib-1.9.3/libdoc/csv/rdoc/CSV.html
3. https://github.com/randym/axlsx/blob/master/examples/example.rb
All rights reserved