Sử dụng Prawn để generrater PDF in Rails
Trong một số dự án, đôi lúc chúng ta cần tạo ra file PDF để hiển thị một CV của ứng viên hay là hóa đơn thanh toán v.v... Hiện nay, trong Ruby đã có rất nhiều những thư viện để hỗ trợ cho lập trình viên tạo file PDF một cách nhanh chóng và hiệu quả. Một trong số đó là gem prawn(readme). Trong ...
Trong một số dự án, đôi lúc chúng ta cần tạo ra file PDF để hiển thị một CV của ứng viên hay là hóa đơn thanh toán v.v...
Hiện nay, trong Ruby đã có rất nhiều những thư viện để hỗ trợ cho lập trình viên tạo file PDF một cách nhanh chóng và hiệu quả.
Một trong số đó là gem prawn(readme). Trong bài viết này sẽ trình bày các bước để tạo một file PDF trong Rails sử dụng prawn.
Để cài đặt praw vào ứng dụng Rails rất đơn giản, ta chỉ cần khai báo dòng gem "prawn" vào trong Gemfile. Tiếp đó, ta cần chạy lệnh trong terminal
bundle install
Bước 1: Ta cần khai báo PDF Mime::Type vào file config/initializers/mime_types.rb như sau:
Mime::Type.register “application/pdf”, :pdf
Kể từ bây giờ, mỗi khi có request mà mime là PDF thì ứng dụng sẽ trả về nội dung file PDF.
Bước 2: Ta sẽ thực hiện xử lý trong controller để trả về định dạng file PDF. Ví dụ như đoạn code dưới đây:
class InvoicesController < ApplicationController before_filter :authenticate_customer!, :only => [:index, :show] def index @invoices = Invoice.all_invoices(current_customer) end def show @invoice = Invoice.find(params[:id]) respond_to do |format| format.html format.pdf do pdf = InvoicePdf.new(@invoice, view_context) send_data pdf.render, filename: "invoice_#{@invoice.created_at.strftime("%d/%m/%Y")}.pdf", type: "application/pdf" end end end end
Trong đoạn code trên, chúng ta đã có thay đổi format của respond theo hai định dạng là html và pdf. Và bên trong block format.pdf, ta có gọi phương thức send_data với các tham số là nội dung file, tên file, và kiểu ứng dụng để đọc file. Ngoài ra, hàm này còn có thêm một option nữa là disposition: "inline" có tác dụng sẽ hiển thị file PDF ngay trên trình duyệt thay vì phải download về máy client.
Bước 3: Ta sẽ tiến hành việc định dạng file PDF cần được tạo ra bằng cách sử dụng praw. Việc này được thực hiện trong lớp InvoicePdf kế thừa lớp Prawn::Document trong thư viện praw.
class InvoicePdf < Prawn::Document def initialize(invoice, view) super() text "This is an order invoice", size: 16, font: "Helvetica", color: "0000FF" end end
Đoạn code trên sử dụng phương thức text của praw để hiển thị trong file PDF với kích thước chữ là 16, font là Helvetica và chữ màu xanh. Tương tự, ta đều có thể hiển thị các dòng text khác bằng cách sử dụng lại phương thức này.
Khi tạo một hóa đơn thì chúng ta thường in logo của công ty. Như vậy làm sao ta có thể tạo hình ảnh trong file PDF?. Điều này trở thành vô cùng đơn giản với việc sử dụng phương thức image của thư viện. Ví dụ, ta muộn hiển thị ảnh ở giữa file với kích thước là 50x50 sẽ thực hiện như sau:
def logo logopath = "#{Rails.root}/app/assets/images/logo.png" open(logopath), fit: [500, 500], position: :center end
Moving Around##
Đây là một tính năng giúp chúng ta có thể xác định chính xác vị trí muốn đặt từng phần tử text or image... trong tài liệu bằng cách di chuyển vị trí con trỏ chuột đến tọa độ mong muốn thông qua các hàm move_down(n), move_up(n) hoặc move_cursor_to(n). Lưu ý đó là trục tọa độ của trang tài liệu có gốc [0, 0] là ở vị trí cuối cùng bên trái trang và trục dương hướng lên trên.
Ngoài ra, thư viện praw, còn cho phép chúng ta trình bày tài liệu dưới dạng bảng bằng cách sử dụng phương thức table, row và column.
Sau đây là code của lớp InvoicePdf để hiển thị một Invoice dưới dạng PDF để các bạn tham khảo cho việc định dạng 1 file PDF đơn giản
class InvoicePdf < Prawn::Document def initialize(invoice, view) super() @invoice = invoice @view = view logo thanks_message subscription_date subscription_details subscription_amount regards_message end def logo logopath = "#{Rails.root}/app/assets/images/logo.png" image logopath, awidth: 197, height: 91 move_down 10 draw_text "Receipt", at: [220, 575], size: 22 end def thanks_message move_down 80 text "Hello #{@invoice.customer.profile.first_name.capitalize}," move_down 15 text "Thank you for your order.Print this receipt as confirmation of your order.", indent_paragraphs: 40, size: 13 end def subscription_date move_down 40 text "Subscription start date: #{@invoice.start_date.strftime("%d/%m/%Y")} ", size: 13 move_down 20 text "Subscription end date : #{@invoice.end_date.strftime("%d/%m/%Y")}", size: 13 end def subscription_details move_down 40 table subscription_item_rows, awidth: 500 do row(0).font_style = :bold columns(1..3).align = :right self.header = true self.column_awidths = {0 => 200, 1 => 100, 2 => 100, 3 => 100} end end def subscription_amount subscription_amount = @invoice.calculate_subscription_amount vat = @invoice.calculated_vat delivery_charges = @invoice.calculated_delivery_charges sales_tax = @invoice.calculated_sales_tax table ([["Vat (12.5% of Amount)", "", "", "#{precision(vat)}"] , ["Sales Tax (10.3% of half the Amount)", "", "", "#{precision(sales_tax)}"] , ["Delivery charges", "", "", "#{precision(delivery_charges)} "], ["", "", "Total Amount", "#{precision(@invoice.total_amount) } "]]), :awidth => 500 do columns(2).align = :left columns(3).align = :right self.header = true self.column_awidths = {0 => 200, 1 => 100, 2 => 100, 3 => 100} columns(2).font_style = :bold end end def subscription_item_rows [["Description", "Quantity", "Rate", "Amount"]] + @invoice.subscriptions.map do |subscribe| [ "#{subscribe.description} ", subscribe.quantity, "#{precision(subscribe.rate)} ", "#{precision(subscribe.quantity * subscribe.rate)}" ] end end def precision(num) @view.number_with_precision(num, :precision => 2) end def regards_message move_down 50 text "Thank You," ,indent_paragraphs: 400 move_down 6 text "XYZ", indent_paragraphs: 370, :size: 14, style: :bold end end
Bước cuối cùng: Ta thêm link của file PDF vào trong views: app/views/invoices/show.html.erb:
<%= link_to "Download invoice", invoice_path(invoice.id, format: "pdf") %>;
Trên đây là bài giới thiệu cơ bản về cách sử dụng praw trong rails. Ngoài ra, các bạn có thể tham khảo thêm các phương thức khác ở đây
Tham khảo: http://www.sitepoint.com/hackable-pdf-typesetting-in-ruby-with-prawn/