Giới thiệu Gem Wicked PDF trong Rails
Bài đăng này đã không được cập nhật trong 7 năm
Giới thiệu
Ở bài viết này mình xin giới thiệu về gem wicked_pdf. Gem Wicked PDF giúp bạn chỉ cần viết một trang HTML như bình thường, sau đó nó sẽ giúp bạn tạo file PDF 1 cách dễ dàng bằng việc sử dụng các tiện ích wkhtmltopdf để tạo file PDF. Wicked PDF làm việc trên ruby 1.8.7 -> 2.3 và rails 2 -> 5
Cách cài đặt wicked pdf
- thêm gem 'wicked_pdf
vào gemfile và
bundle install` - sau đó khởi tạo
initializer
bằng câu lệnh :rails generate wicked_pdf
- với những phiên bản rails 4 trở xuống bạn cần config thêm trong file
config/initializers/mime_types.rb
:Mime::Type.register "application/pdf", :pdf
Như đã nói ở trên wicked_pdf dùng wkhtmltopdf để tạo file PDF nên chúng ta cần cài đặt thêmgem 'wkhtmltopdf-binary'
và bundle install Nếuwkhtmltopdf
không cùng nằm trên 1 server thì chúng ta cần thêm config:
WickedPdf.config = {
exe_path: '/usr/local/bin/wkhtmltopdf'
}
trong file config/initializers/wicked_pdf.rb
Vậy là đã xong phần cái đặt.
Cách dùng wicked pdf
Tạo controller để xử lý việc export pdf
class WickedPdfsController < ApplicationController
def index
respond_to do |format|
format.html
format.pdf do
render pdf: "name_file"
end
end
end
ở đây mình dùng wicked pdf để render ra file pdf. Các bạn có thể config thêm ở đây:
pdf: "file_name", #file name pdf
disposition: "attachment", #file pdf sau khi tạo sẽ tự động download về máy
template: "things/show.pdf.erb", #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).
file: "#{Rails.root}/files/foo.erb"
layout: "pdf.html",
wkhtmltopdf: "/usr/local/bin/wkhtmltopdf", #path thư viện wkhtmltopdf
show_as_html: params.key?("debug"), #Debugging
orientation: "Landscape",
page_size: "A4, Letter, ...", # size hiển thị trên pdf
page_height: NUMBER, #chiều cao của file
page_width: NUMBER, #động rộng của file
save_to_file: Rails.root.join("pdfs", "#{filename}.pdf"), #path khi download file
save_only: false, #chỉ lưu file (phụ thuộc vào save_to_file đã được thiết lập sẵn)
proxy: "TEXT",
basic_auth: false #authenticate khi tạo file pdf
username: "TEXT", #tài khoản của account authenticate
password: "TEXT", #mật khẩu của account authenticate
title: "Alternate Title", #title của pdf
cover: "URL, Pathname, or raw HTML string",
dpi: "dpi",
encoding: "TEXT",
user_style_sheet: "URL",
cookie: ["_session_id SESSION_ID"],
post: ["query QUERY_PARAM"],
redirect_delay: NUMBER,
javascript_delay: NUMBER,
window_status: "TEXT",
image_quality: NUMBER,
no_pdf_compression: true,
zoom: FLOAT,
page_offset: NUMBER,
book: true,
default_header: true,
disable_javascript: false,
grayscale: true,
lowquality: true,
enable_plugins: true,
disable_internal_links: true,
disable_external_links: true,
print_media_type: true,
disable_smart_shrinking: true,
use_xserver: true,
background: false,
no_background: true,
viewport_size: "TEXT",
extra: "",
outline: { outline: true,
outline_depth: LEVEL },
margin: { top: SIZE,
bottom: SIZE,
left: SIZE,
right: SIZE },
header: { html: { template: "users/header.pdf.erb",
layout: "pdf_plain.html",
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"},
footer: { html: { template:"shared/footer.pdf.erb",
layout: "pdf_plain.html",
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"},
toc: { font_name: "NAME",
depth: LEVEL,
header_text: "TEXT",
header_fs: SIZE,
text_size_shrink: 0.8,
l1_font_size: SIZE,
l2_font_size: SIZE,
l3_font_size: SIZE,
l4_font_size: SIZE,
l5_font_size: SIZE,
l6_font_size: SIZE,
l7_font_size: SIZE,
level_indentation: NUM,
l1_indentation: NUM,
l2_indentation: NUM,
l3_indentation: NUM,
l4_indentation: NUM,
l5_indentation: NUM,
l6_indentation: NUM,
l7_indentation: NUM,
no_dots: true,
disable_dotted_lines: true,
disable_links: true,
disable_toc_links: true,
disable_back_links:true,
xsl_style_sheet: "file.xsl"}
Mọi người có thể tham khảo thêm ở trên https://github.com/mileszs/wicked_pdf.
Thêm Css & JS trong view PDF
bới vì thư viện wkhtmltopdf đang chạy ngoài ứng dựng rails của bạn nên layout thông thường sẽ không thể hoạt động được. Muốn sử dụng được css, javascript các bạn hãy sử dụng wicked_pdf_stylesheet_link_tag
, wicked_pdf_javascript_include_tag
và wicked_pdf_image_tag
hoặc trỏ thẳng đến một CDN cho các thư việc của jquery
VD:
<!DOCTYPE html>
<html>
<head>
<title><%= full_title yield :title %></title>
<%= wicked_pdf_stylesheet_link_tag "admin/pdf" %>
<%= wicked_pdf_stylesheet_link_tag "admin/users" %>
<%= wicked_pdf_javascript_include_tag "admin/pdf" %>
<%= 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 %>
<%=wicked_pdf_image_tag "admin/image.png"%>
</body>
</html>
Sử dụng Bootstrap trong PDF
trong lúc sử dụng wicked_pdf mình đã rất khốn khổ về việc không thể include bootstrap vào khi render pdf. Khi đường dẫn trong thư viện wkhtmltopdf đòi hỏi bạn phải sử dụng đường dẫn tuyệt đối. Đầu tiên bạn tạo 1 file pdf.css.scss và sử dụng đường dẫn tuyệt đối của wicked_pdf
#pdf.css.scss
@import "bootstrap-sprockets";
@import "bootstrap";
@import "mixin";
@import "flexslider";
trong view include file pdf.css.scss
<%= wicked_pdf_stylesheet_link_tag "sass/pdf" %>
Sử dụng nâng cao
Tạo pdf từ 1 string
pdf = WickedPdf.new.pdf_from_string("ceate a pdf from a string")
Tạo pdf từ 1 html
pdf = WickedPdf.new.pdf_from_html_file("your_path")
Tạo pdf từ 1 url
pdf = WickedPdf.new.pdf_from_url("url)
Tạo file PDF từ string sử dụng template
, layouts
và nội dung tùy chọn (header
, footer
)
string = ApplicationController.new.render_to_string(
template: "pc/orders/details.pdf.slim",
layout: "pc/layouts/pdf.slim",
locals: {:@order => order}
)
pdf = WickedPdf.new.pdf_from_string string, encoding: "UTF-8"
Lưu 1 file pdf
File.open(save_path, "wb") do file|
file << pdf
end
Ngắt trang trong PDF
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.
div.alwaysbreak { page-break-before: always; }
div.nobreak:before { clear:both; }
div.nobreak { page-break-inside: avoid; }
Đánh số trang
Bạn có thể đánh số trang với 1 đoạn code js:
<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>
Rack Middleware
Nếu bạn muốn wicked_pdf render các trang view bằng cách nối thêm .pdf
vào url :
thêm
require 'wicked_pdf'
config.middleware.use WickedPdf::Middleware
Debugging
ở phần config có nói đến Debugging. Cho phep bạn có thể truyền tham số param lên url
show_as_html: params.key?('debug')
Kết bài
Nguồn tham khảo: https://github.com/mileszs/wicked_pdf Như vậy mình đã giới thiệu xong gem wicked_pdf. Cảm ơn mọi người đã theo dõi bài viết
All rights reserved