12/08/2018, 14:22

Export pdf in rails app

PDF Các file pdf hiện nay là một format được nhiều người ưu chuộng vì tính thuận tiện trong việc trao đổi thông tin. Tính thuận tiện được thể hiện: người đọc không thể thay đổi nội dung của file, phần mềm đọc pdf không phải phụ thuộc vào các phiên bản, hay phông chữ giống như office. Chính vì ...

PDF

Các file pdf hiện nay là một format được nhiều người ưu chuộng vì tính thuận tiện trong việc trao đổi thông tin. Tính thuận tiện được thể hiện: người đọc không thể thay đổi nội dung của file, phần mềm đọc pdf không phải phụ thuộc vào các phiên bản, hay phông chữ giống như office. Chính vì những lý do trên mình sẽ viết một ví dụ về kĩ thuật export file pdf trong rails app. Hy vọng bạn sẽ thấy bài viết có ích

html_to_pdf.png

Trong bài viết này mình có sử dụng gem wicked pdf. Đây là link của của gem: https://github.com/mileszs/wicked_pdf.

1. Add gem wicked pdf in rails app

Thêm vào Gemfile dòng dưới đấy, sau đó gõ bundle install:

 gem 'wicked_pdf'

Sau đó tiếp tục gõ:

rails generate wicked_pdf

Sau khi gõ lệnh trên file config/initializers/wicked_pdf.rb sẽ tự động được sinh ra bởi rails app. Đây là file config chung cho wicked pdf.

Thêm dòng sau vào trong thư mục config/initializers/mime_types.rb với các bản rails cũ

Mime::Type.register "application/pdf", :pdf

Tuy nhiên đến đấy vẫn chưa config xong bạn còn phải thêm gem:

gem 'wkhtmltopdf-binary'

Gõ bundle install (Để hiểu rõ hơn bạn có thể vào đây để tham khảo: http://wkhtmltopdf.org/). Trong bài viết này mình sẽ thực hiện export profile user ra filf pdf.

2. Basic Usage

Tạo một controller riêng để xử lý việc export file pdf. Giả sử mình sẽ tạo controller có tên "pdf"

rails g controller Pdfs

Trong controller pdf có một phương thức show để xử lý việc export.

class PdfsController < ApplicationController

  def show
    @user = User.find_by id: params[:user_id]
    respond_to do |format|
      format.html
      format.pdf do
        render pdf: "#{@user.name}_#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}",
          template: "pdfs/show.html.erb",
          disposition: "attachment",
          layout: "pdf",
          orientation: "Landscape",
          encoding: "UTF-8"
      end
    end
  end
end

Mình sẽ giải thích một số thuộc tính mình sử dụng ở trên: render

  • pdf: Tên của file sau khi generate.

  • template: Wicked_pdf sẽ render từ html sang pdf (nói cách khác phần view mà hiển thị trên trang web sẽ được chuyển thành file pdf).

  • disposition: file pdf sau khi tạo sẽ được tự động download về máy

  • layout: wicked_pdf sẽ tự động tìm kiếm trong thư mục layouts của view file có tên pdf.html.erb (app/views/layouts/). Thay vì sử dụng layout application.html.erb wicked_pdf sẽ sử dụng layout pdf mà mình tạo được(cái này quan trọng nhé mình sẽ giải thích sau)

  • Đối với các phần còn lại các bạn có thể tham khảo ngày tại trang trủ của gem còn rất nhiều thuộc tính khác có thể sử dụng, trên đây là một số tính năng cơ bản.

3. Tip and trick

Add css to view in pdf

Với các bước như trên thì bạn đã có một tính năng export ra file pdf tuy nhiên như thể là chưa đủ vì sau khi export: css của view sẽ không có. Là do wkhtmltopdf binary chạy ở ngoài luồng của ứng dụng rails, chính vì thể wicked pdf sẽ không thể hiểu cơ chế asset pipeline của rails cũng như applications layout sẽ không hoạt động.

Do đó để nếu bạn muốn sử dụng css hoặc ảnh thì bạn phải sử dụng template khác đó là lý do tại sao ở phần basic useage mình có thêm thuộc tính là layout: "pdf". Wicked cung cấp các phương thức để chỉ ra file css, image, javascript nào sẽ được sử dụng . Ví dụ trong pdf layout của mình sư sau:

 <!DOCTYPE html>
<html>
  <head>
    <title><%= full_title yield :title %></title>
    <%= wicked_pdf_stylesheet_link_tag "admin/pdf" %>
    <%= wicked_pdf_stylesheet_link_tag "admin/users" %>
    <%= csrf_meta_tags %>
    <meta name="turbolinks-cache-control" content="no-cache">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
  </head>
  <body>
    <%= yield %>
  </body>
</html>

Và một số các helper khác như sau: wicked_pdf_image_tag (sử dụng trong view để thay cho image_tag), wicked_pdf_javascript_include_tag

Page Breaks

Việc render từ html sang pdf không thể đảm bảo wicked pdf sẽ hiển thị đúng như ý muốn do độ dài của các phần là khác nhau. Do đó wicked cung cấp css để hạn chế tình trạng ngắt dòng không đúng

#users{
  .alwaysbreak { page-break-before: always; }
  .nobreak:before { clear:both; }
  .nobreak { page-break-inside: avoid; }
}

Wicked_pdf with bootstrap

Như mình đã nói giới thiệu ở trên wkhtmltopdf binary sẽ không hiểu cơ chế asset pipeline của rails do đó wicked_pdf không hiểu cơ chế col sm/md/lg của bootstrap. Để giải quyết vấn đề mình sẽ tạo file pdf.css.scss và sử dụng đường dẫn tuyệt đối của wicked_pdf:

@import "bootstrap-sprockets";
@import "bootstrap";
@import "mixin";
@import "flexslider";

@include make-grid(sm);
@include make-grid(md);
@include make-grid(lg);

#users {
  .alwaysbreak {
    page-break-before: always;
  }

  .nobreak:before {
    clear:both;
  }

  .nobreak {
    page-break-inside: avoid;
  }
}

Bài viết đến đây là kết thúc. Xin chân thành cảm ơn.

Tham khảo

Bài viết có sự tham khảo từ blog : https://github.com/mileszs/wicked_pdf

0