12/08/2018, 14:23

Tìm hiểu thêm về gem Wiked PDF

Trong công việc đôi khi bạn gặp phải task export dữ liệu thành dạng PDF, gem Wicked PDF được sử dụng khá phổ biến, việc hiểu rõ thêm gem này gíup bạn chủ động hơn trong việc export dữ liệu. Link đến gem: https://github.com/mileszs/wicked_pdf Vì gem wiked pdf khá lớn, trong giới hạn của bài ...

Trong công việc đôi khi bạn gặp phải task export dữ liệu thành dạng PDF, gem Wicked PDF được sử dụng khá phổ biến, việc hiểu rõ thêm gem này gíup bạn chủ động hơn trong việc export dữ liệu.

Link đến gem: https://github.com/mileszs/wicked_pdf

Vì gem wiked pdf khá lớn, trong giới hạn của bài viết, mình xin trình bày về phần header.

Khi muốn đưa header vào dữ liệu export ra ta thường có:

render pdf: 'file_name',
  ...
  header:
    html: {
      template: 'users/header',
      layout:   'pdf_plain',
      url:      'www.example.com',
      locals:   { foo: @bar }
    },
    center:            'TEXT',
    font_name:         'NAME',
    font_size:         SIZE,
    left:              'TEXT',
    right:             'TEXT',
    spacing:           REAL,
    line:              true,
    content:           'HTML CONTENT ALREADY RENDERED'

html trong header được render qua các trường template, layout, url, locals, ta có thể đưa vào 1 partial để render vào header.

Giả sử ta có file header: (header.slim)

doctype html

h3 = "Test Header"

Khi render thì thêm vào như sau:

header: {html: {template: "header.slim"}} ...

Kết qủa được là:

header.png

Chú ý setting doctype html để header được hiện ra trong export.

Phần content khá gần giống với html tuy nhiên dữ liệu đưa vào content là dạng HTML đã được render ra. Ta có thể dùng hàm render_to_string, khi dùng content thì sẽ đưa vào như sau:

header: {content: ActionController::Base.new.render_to_string "header.slim"}

Kết qủa nhận được giống như khi đưa vào theo html, khi render trong 1 controller thì có thể gọi trực tiếp render_to_string còn khi gọi ở service hoặc job chạy nền thì cần ActionController::Base.new

Khi render dùng html hoặc content trong header phần background của header sẽ che phần area của document nằm dưới nó, để tránh trường hợp này, ta có thể dùng center để đưa text vào và không che mất phần document ở phía dưới.

header: {center: "Test Header", font_size: 20, spacing: -5},

Kết qủa được là:

header1.png

Trong trường hợp trên, font_size là gía trị set cho kích thướct to nhỏ của font, spacing chính là khoảng cách từ phía trên trang document tới text đưa vào center

Để có đoạn text xuất hiện bên phải header ta dùng right:

header: {
  center: "Test Header",
  right: "Test Right",
  font_size: 20,
  spacing: -5
},

Kết qủa được là

right.png

Muốn có những phần xuống dòng ta thêm như xử lý text thông thường

header: {
  center: "Test Header",
  right: "Test Right
Test Right
Test Right",
  font_size: 15,
  spacing: -5
},

Kết qủa được là

rightln.png

Có thể đưa vào page và total page bằng cách thêm [page] / [topage]

header: {
  center: "Test Header",
  right: "[page] / [topage]",
  font_size: 15,
  spacing: -5
},

Kết qủa được là

page.png

Nếu bạn muốn đưa page và topage vào header thì nên dùng javascript trong wicked pdf

<html>
  <head>
    <script>
      function number_pages() {
        var vars={};
        var x=document.location.search.substring(1).split('&');
        for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = decodeURIComponent(z[1]);}
        var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
        for(var i in x) {
          var y = document.getElementsByClassName(x[i]);
          for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
        }
      }
    </script>
  </head>
  <body onload="number_pages()">
    Page <span class="page"></span> of <span class="topage"></span>
  </body>
</html>

Cảm ơn và hi vọng bài viết giúp ích cho bạn trong công việc.

0