Installation
Firstly, navigate to your project working directory then copy the following lines in your Gemfile and run ‘bundle install’ from the terminal.
gem 'wicked_pdf' gem 'wkhtmltopdf-binary' gem 'wkhtmltopdf-binary-edge'
Add or modify config/initializers/mime_types.rb file to register the PDF mime type.
Mime::Type.register "application/pdf", :pdf
Now run following command to generate initial configurations.
rails generate wicked_pdf
This will create wicked_pdf.rb under config/initializers.
Setup
Now the controller needs to be set up for rendering the PDF. Add following respond_to block in your controller action method that will generate the PDF view.
respond_to do |format| format.html format.pdf do render template: 'companies/show', pdf: 'Company Detail Report-' + Time.now.strftime('%v %H:%M:%S').to_s, javascript_delay: 10000, layout: 'pdf_layout.html.haml', disposition: 'attachment' end end
Specifying the disposition as ‘attachment’ will download the page as PDF and setting it as ‘inline’ will simply generate a PDF in a new tab.
Make a separate layout file, which the PDF view will use. For example, here pdf_layout.html. HTML is created in the layouts folder. As wicked_pdf cannot identify assets pipeline, the HTML structure needs to be added to the layout HTML file.
!!! %html{ lang: 'en' } %head %body = yield
In order to access any custom CSS or bootstrap class, add the following helpers to the head in the layout file.
= stylesheet_link_tag "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" = wicked_pdf_stylesheet_link_tag 'dashboard', media: 'all', 'data-turbolinks-track' => true = wicked_pdf_stylesheet_link_tag('bootstrap')
You can add assets CSS and Javascript in application.css and application.js files.
Application.js:
//= require highcharts //= require highcharts/highcharts-more //= require turbolinks //= require bootstrap-sprockets //= require bootstrap-select
Application.css :
@import 'bootstrap-sprockets'; @import 'bootstrap'; @import 'bootstrap-select';
The extension of the view file should be as such, .pdf.haml.
Add the link to generate the PDF file as follows:
= link_to companies_path(@company, format: :pdf), target: '_blank', title: 'Click to Export as PDF', class: 'btn btn-default' do %i.glyphicon.glyphicon-download-alt Export as PDF
Graph generation
The project I was working on required several interactive graphs, which I further needed to display in my PDF viewer. I used a javascript framework Highcharts, which I integrated with Wicked PDF Here’s an easy way to render Highcharts graph in your PDF. Firstly, add the followings in your layout file.
%script{:src => "https://code.highcharts.com/highcharts.js"} %script{:src => "https://code.highcharts.com/highcharts-more.js"} %script{:src => "https://code.highcharts.com/modules/exporting.js"}
Next in pdf.haml, where the graph will be rendered, simply add the javascript path where you have created the graph. The format and a javascript delay need to be added, along with any necessary parameters that need to be passed to create the graph. The javascript delay denotes the time taken to load the graph.
= render partial: 'companies/pie_chart, formats: [:html], :javascript_delay => 10000, locals: { gross_profit: @gross_profit}
While rendering the chart, elements like animation may delay it to the extent of not rendering the graph in time. This is an optional step, but just to be safe the followings could be added to the file containing the charts.
plotOptions: { series: { enableMouseTracking: false, shadow: false, animation: false } }
Page Number
Numbering pages is an important aspect of any PDF. In the ‘onload’ of the body in the PDF layout, call number_pages() function. The js function of number_pages(), will contain the following:
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]] = unescape(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]]; } }
To add the page number as footer add it to your controller as shown below. Its size can be changed with: font_size element.
render template: 'companies/show', pdf: 'Company Detail Report-' + Time.now.strftime('%v %H:%M:%S').to_s, javascript_delay: 10000, layout: 'pdf_layout.html.haml', disposition: 'attachment', viewport_size: '1280x1024', :footer => { :right => 'Page [page] of [topage]', :font_size => 7 }
Displaying an Image
To insert an image in PDF, one must use the pdf_image_tag helper. Adjust the height and width of the image accordingly. The images can be kept conventionally inside assets/images folder.
wicked_pdf_image_tag( 'growth.png', height: '15', width: '15')
Page Break
To force a page break before a new page adds the following CSS in your CSS file:
.page-break { display:block; clear:both; page-break-before:always; }
Just change to page-break-after: always; for enforcing page break at the end of a page.
Now you’ll have a PDF generated from a rails view up and running, with some common but essential features!
Contributor: Mehreen Mansur, Nascenia