Asitha Bandara
Today's blog post isabout exporting PDFs in a Ruby on Rails project. We will discuss how to achievethe following tasks:
1. Generatecontent as PDF
2. Handle thePDF generation as a background job
3. Make thelink available in an email for download purposes
Generate content as PDF
For this section, thefollowing Gem is used out of many libraries which does the same thing.
gem 'wicked_pdf'
gem 'wkhtmltopdf-binary'
If you want to take alook inside this library here is the link.
This awesome librarymakes PDF generation easy. These are the steps that were followed:
1. Add theGem into the file and install it.
2. Change the required method with respond_to block.
respond_to do |format|
format.html
format.pdfdo
html =render_to_string template: "pdf/diary.pdf"
folder ="#{@diary.id}_#{@diary.child_name}_#{@year}"
file_name= "#{@diary.child_name}"
pdf =WickedPdf.new.pdf_from_string(html)
file_name= "#{file_name}-#{year}"
save_path=Rails.root.join("public/export/#{folder}","#{file_name}.pdf")
File.open(save_path, 'wb') do |file|
file<< pdf
end
redirect_to finish_download_content_index_path, notice: t('download_link_will_be_sent_to_your_email')
end
end
For this, a separatetemplate for the PDF generation had to be created and it is referenced in,
html = render_to_string template: "PDF template file"
Those files are added ina folder named “PDF” under the view directory as below:
Wicked PDF librarygenerates the PDF from the HTML string. So we can parse the string into thewicked PDF library as follows.
pdf = WickedPdf.new.pdf_from_string(html)
html refers to thestring that is rendered from the template.
That’s all here; butthere is a slight issue when this string is huge. It will hold the server untilit completes the PDF generation. Therefore this process needs to be in thebackground, so that it’ll generate the PDF without interrupting the mainthread.
How to handle PDF generation asa background job?
For this, the RailsActive Job facility can be used. First, create a class to perform thisoperation.
To create a new job:
rails generate job pdfs_generate
Those jobs will be savedin a new folder named "Jobs”.
For the Job execution aqueuing library is required. There are many such libraries. Some examples arebelow.
· Sidekiq
· Resque
· Sneakers
· Sucker Punch
· Queue Classic
· Delayed Job
Let's use the “DelayedJob” library:
gem'delayed_job_active_record'
It is time to embed thewicked PDF generation process inside the Job class now.
Note:
There are two mainthings in a JOB.
1. Perform method
2. Call backs →after_perform, before_perform etc.
Perform method willcarry out the process in the background. Once it is completed, it will call the"callback method" named as “after_perform”, which will be used tosend the email after the PDF generation process.
Here is the PDF generateJob class file.
class PdfsGenerateJob< ActiveJob::Base
queue_as:default
after_perform do|job|
puts"****************************************"
puts"************** DONE !!!!!!! *************"
puts"****************************************"
puts"Email should sent to : #{@user_email}"
puts"Diary Id: #{@diary_id}"
puts"****************************************"
# Sending theemail
DownloadMailer.send_download_pdf_link(@user_email, @folder,@file_name).deliver_now
end
defperform(html, folder, file_name, user_email, year, diary, year_start_date,year_end_date)
pdf =WickedPdf.new.pdf_from_string(html)
file_name ="#{file_name}-#{year}"
save_path = Rails.root.join("public/export/#{folder}","#{file_name}.pdf")
File.open(save_path, 'wb') do |file|
file<< pdf
end
@user_email =user_email
@diary_id =diary.id
@folder =folder
@file_name =file_name
end
end
Show method was changedby getting the perform function in a new thread in order to call the Jobprocess and to call the perform function using the later postfix.
respond_to do |format|
format.html
format.pdfdo
Thread.newdo
html =render_to_string template: "pdf/diary.pdf"
folder ="#{@diary.id}_#{@diary.child_name}_#{@year}"
file_name = "#{@diary.child_name}"
PdfsGenerateJob.perform_later(html, folder, file_name,@current_user.email, @year, @diary, @year_start_date, @year_end_date)
end
redirect_tofinish_download_content_index_path, notice:t('download_link_will_be_sent_to_your_email')
end
end
Wicked PDF generationwill happen in a new thread in the background. Therefore, it won't affect themain rails process. User is free to do any other work.
rails generate jobguests_cleanup
According to this code,once the PDF work is completed, it will send the email to the current user asdescribed above. (remind → after_perform callback).
Hope the process isclear to you. Please feel free to comment below if you have any questions.