Exporting CSV, Excel and Docx
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 ...
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 trong app/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 định style cho row + colum trong file excel thì sử dụng lệnh add_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, awidth 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.awidth, image.height = awidth, height if awidth && 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) //awidth : độ 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ác option 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/header 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