📜 ⬆️ ⬇️

PDF generation with Prawn

Prawn Rails PDF
Introduction

In the topic, I will consider creating PDF documents using Ruby / Rails, generating them, downloading directly from the site or creating a rake task, as well as the possibility of sending as an attachment through Mailer.
We will work with Rails 3.0.9 and gem'om Prawn.


Install prawn

Bundler

gem 'prawn', :git => "git://github.com/sandal/prawn.git", :submodules => true 


Rail Integration

Create a directory for report classes:
$ mkdir app/reports

For autoloading classes from this directory in config / application.rb add:
 config.autoload_paths << "#{Rails.root}/app/reports" 

And register the mime type (config / initializers / mime_types.rb)
 Mime::Type.register_alias "application/pdf", :pdf 

Include gem in autoload (after creating the file) config / initializers / prawn.rb
 require "prawn" 

Check if Prawn works (I use RVM)
 $ rails c Loading development environment (Rails 3.0.9) ruby-1.9.2-p180 :001 > Prawn::BASEDIR => "/home/kir/.rvm/gems/ruby-1.9.2-p180@pdfer/bundler/gems/prawn-1288242ddece" 

We generate PDF

In order for Prawn to support Cyrillic, you need to provide it with Russian fonts. Put them in your home directory, I have this / home / kir / prawn_fonts. "Verdun", tested in working with Prawn, I posted here .
')
To have a table with data, create a scaffolder with the Customer model.

rails g scaffold customer name:string amount:float
rake db:migrate


Fill the table with any data.

Now you can create a report file generator. Let it be app / reports / customers_report.rb with the following code:

 # encoding: utf-8 class CustomersReport < Prawn::Document #   Widths = [200, 200, 120] #   Headers = [' ', '', ''] def row(date, customer_name, amount) row = [date, customer_name, amount] make_table([row]) do |t| t.column_widths = Widths t.cells.style :borders => [:left, :right], :padding => 2 end end def to_pdf #   font_families.update( "Verdana" => { :bold => "/home/kir/prawn_fonts/verdanab.ttf", :italic => "/home/kir/prawn_fonts/verdanai.ttf", :normal => "/home/kir/prawn_fonts/verdana.ttf" }) font "Verdana", :size => 10 text "  #{Time.zone.now.strftime('%b %Y')}", :size => 15, :style => :bold, :align => :center move_down(18) #   @customers = Customer.order('created_at') data = [] items = @customers.each do |item| data << row(item.created_at.strftime('%d/%m/%y %H:%M'), item.friendly_name, item.) end head = make_table([Headers], :column_widths => Widths) table([[head], *(data.map{|d| [d]})], :header => true, :row_colors => %w[cccccc ffffff]) do row(0).style :background_color => '000000', :text_color => 'ffffff' cells.style :borders => [] end #      creation_date = Time.zone.now.strftime("  %e %b %Y  %H:%M") go_to_page(page_count) move_down(710) text creation_date, :align => :right, :style => :italic, :size => 9 render end end 

PDF generator is ready. Add an action to the controller that will be responsible for downloading the PDF.
 def download_pdf output = CustomersReport.new.to_pdf send_data output, :type => 'application/pdf', :filename => "customers.pdf" end 

Do not forget to prescribe the route for this action! For example:
 resources :customers do collection do get 'download_pdf' end end 

Go to the address / customers / download_pdf . The result is such a document .

rake task


But let's say that we want to generate PDF through the rake task. Consider the implementation (code lib / tasks / customers_report.rake):
 namespace :customers_report do desc 'Generates report with customers' task :generate_pdf => :environment do output = CustomersReport.new.to_pdf filename = "report.pdf" File.open(Rails.root.join('public', filename), 'wb') do |f| f.write(output) end puts "Report was written to #{filename}" end end 

Run: rake customers_report:generate_pdf --trace
The report will be generated in public / report.pdf.

rake task + mailer


Another situation: PDF should be sent monthly by e-mail. To do this, we need to create a mailer and another task.
Generate mailer: rails g mailer customers_mailer report_email and change the code app / mailers / customers_mailer.rb:
 class CustomersMailer < ActionMailer::Base default :from => "me@yandexteam.ru" #   ! def report_email(pdf_output, to) report_filename = Time.zone.now.strftime('Report %d-%m-%Y') attachments[report_filename] = { :mime_type => 'application/pdf', :content => pdf_output } mail(:to => to, :subject => report_filename.titleize) end end 

And also prescribe a task to send it (the same lib / tasks / customers_report.rake):
 namespace :customers_report do desc 'Generates report with customers' task :generate_pdf => :environment do #... end desc 'Send report by email' task :send_by_email => :environment do #    # recipient = ["vasya@gmail.com", "petya@gmail.com"] recipient = 'me@yandexteam.ru' #   ! output = CustomersReport.new.to_pdf CustomersMailer.report_email(output, recipient).deliver puts "Report was sent to #{recipient}" end end 

Is done. Do not forget to specify the real addresses and settings action_mailer in the parameters of the environment!
Checking performance: rake customers_report:send_by_email --trace

References:

The Prawn repository on Github: https://github.com/sandal/prawn/
My repository with the demo application described in the article: https://github.com/kirs/pdfer
About installing Prawn on GitHub: https://github.com/sandal/prawn/wiki/Using-Prawn-in-Rails
PS Many thanks to Dmitry Galinsky from evrone for the April presentation at Rails Club!

Source: https://habr.com/ru/post/120388/


All Articles