Rails 4, ActionMailer & Wicked PDF - ruby-on-rails

Controller method
def email_pdf
#job = Job.find_by_id(params[:id].to_i)
job_pdf = WickedPdf.new.pdf_from_string(render_to_string(:pdf => 'job', :template => 'job/show.pdf.erb', layout: 'mailer.html.erb'))
JobMailer.send_jobs_email(params[:id].to_i, 'vir.jain#gmail.com', 'Mahavir Jain', job_pdf).deliver_now
respond_to do |format|
format.json do
render :json => {:success => true}, :status => 200
end
end
end
Job Mailer
class JobMailer < ApplicationMailer
def send_jobs_email(job_id, email, name, job_pdf)
#name = name
#job = Job.find_by_id(job_id)
puts 'hello1'
attachments['job'] = job_pdf
puts #name
mail(to: email, subject: 'Job', from: 'info#janatrak.com', from_name: 'JanaTrak Admin')
end
end
Output
Rendered job/show.pdf.erb within layouts/mailer.html.erb (15.0ms)
"***************[\"/usr/local/bin/wkhtmltopdf\", \"-q\", \"file:///var/folders/dk/t3scf65x5vx23qq1fsm53s3r0000gn/T/wicked_pdf20151007-4801-h2de03.html\", \"/var/folders/dk/t3scf65x5vx23qq1fsm53s3r0000gn/T/wicked_pdf_generated_file20151007-4801-7uwh23.pdf\"]***************"
"***************[\"/usr/local/bin/wkhtmltopdf\", \"-q\", \"file:///var/folders/dk/t3scf65x5vx23qq1fsm53s3r0000gn/T/wicked_pdf20151007-4801-mp6b6i.html\", \"/var/folders/dk/t3scf65x5vx23qq1fsm53s3r0000gn/T/wicked_pdf_generated_file20151007-4801-3bayit.pdf\"]***************"
Rendered job_mailer/send_jobs_email.html.erb within layouts/mailer (0.1ms)
[{"email"=>"vir.jain#gmail.com", "status"=>"sent", "_id"=>"dc93087c39a949de827df06a1edb116e", "reject_reason"=>nil}]
Problem
From output, I can see, I am able to generate pdf properly but for some reason, it's not sending pdf as attachment. Also it's not sending email content. But when I remove attachment from code, it do properly send content of email.
I did checked
Rails 3 ActionMailer and Wicked_PDF
and tried both solution but none worked.
I'm using rails 4.2, ruby 2.1.2, wkhtmltopdf 0.12.2.1 (with patched qt).
Any help is really appreciated
***************** UPDATE ************************
Controller Method
def email_pdf
#job = Job.find_by_id(params[:id].to_i)
self.instance_variable_set(:#lookup_context, nil)
self.instance_variable_set(:#_lookup_context, nil)
job_pdf = WickedPdf.new.pdf_from_string(render_to_string(:template => 'job/show.pdf.erb', layout: 'mailer.html.erb'))
#job_pdf = WickedPdf.new.pdf_from_string('<h1>Hello There!</h1>')
save_path = Rails.root.join('pdfs','job.pdf')
dir = File.dirname(save_path)
FileUtils.mkdir_p(dir) unless File.directory?(dir)
File.open(save_path, 'wb') do |file|
file << job_pdf
end
JobMailer.send_jobs_email(params[:id].to_i, 'vir.jain#gmail.com', 'Mahavir Jain', save_path).deliver_now
respond_to do |format|
format.json do
render :json => {:success => true}, :status => 200
end
end
end
Mailer Method
def send_jobs_email(job_id, email, name, job_pdf)
#name = name
#job = Job.find_by_id(job_id)
puts 'hello1'
attachments['job.pdf'] = File.read(job_pdf)
puts job_pdf
mail(to: email, subject: 'Job', from: 'info#janatrak.com', from_name: 'JanaTrak Admin')
end
PDF is generating properly & i can see saved pdf.. But again somehow actionmailer not attaching pdf as well as not displaying content..
Am I anything missing related to actionmailer attachment?

Related

Missing template when attaching pdf to actionmailer and wicked pdf

I get Missing template when trying to send an email with a pdf attachment:
Controller
respond_to do |format|
format.html
format.pdf do
render pdf: "job card ##{#bike_service.id} - #{DateTime.now}", :template => 'bike_services/show.html.erb' # Excluding ".pdf" extension.
end
end
BikeServiceMailer.job_card_pdf_email(BikeService.last.id).deliver_now
end
Mailer
def job_card_pdf_email(bike_service_id)
bike_service = BikeService.find(bike_service_id)
attachments["bike_service_#{bike_service.id}-#{DateTime.now}.pdf"] = WickedPdf.new.pdf_from_string(
render_to_string(pdf: 'bike_service', template: File.join('app', 'views', 'bike_services', 'show.pdf.erb'), layout: 'pdf.html')
)
mail(to: todo.owner.email, subject: 'Your job card PDF is attached', bike_service: bike_service)
end
The show.pdf.erb template is there already.
I think you need to change the render_to_string line to either:
render_to_string(pdf: 'bike_service', template: File.join('bike_services', 'show.pdf.erb'), layout: 'pdf.html')
or
render_to_string(pdf: 'bike_service', template: Rails.root.join('app', 'views', 'bike_services', 'show.pdf.erb'), layout: 'pdf.html')
At the moment, I think the system is looking for app/views/bike_services/show.pdf.erb in /Users/vangama/projects/mm-crm/app/views which is effectively /Users/vangama/projects/mm-crm/app/views/app/views/bike_services/show.pdf.erb which doesn't exist.

ActionMailer without template and multipart email

Rails will helpfully send multipart email if there are multiple template types present (e.g. .txt and .html files for the same mailer action).
However, what if I want to do this without templates? Normally we specify body and content_type as arguments:
mail to: 'a#example.com', subject: 'Hello', body: 'Hi', content_type: 'text/html'
So how can this be achieved with multiple bodies having their own type?
class TestMailer < ActionMailer::Base
def welcome_email
mail(to: 'example#example.com', subject: 'Welcome to My Awesome Site') do |format|
format.html { render html: '<h1>Welcome XYZ!</h1>'.html_safe }
format.text { render plain: 'Welcome XYZ' }
end
end
end
To use it call: TestMailer.welcome_email.deliver_now.
Documentation, section 2.4

Rails 4 Wick_pdf sends attaches blank pdf

I'm using wick_pdf in my Rails 4 app to convert several html templates into pdfs. I then attach these pdfs to an outbound email. The email and the pdfs are sending correctly, but there is an additional blank pdf (occasionally not completely) that gets sent along with my desired pdfs. I've attached my code below. Please let me know if you have any suggestions.
def approval_notification(id)
#user = User.find(id)
esign = WickedPdf.new.pdf_from_string(render_to_string pdf: "esign", template: "disclosures/pdfs/esign_pdf.html.erb", formats: :html, encoding: "UTF-8")
mail(:to => #user.email, :subject => 'Congratulations! You have been approved!') do |format|
format.html
format.pdf do
attachments['Electronic_Signature.pdf'] = esign
end
end
end
Update:
Alright, I managed to fix the issue. I still don't completely understand what was wrong so please explain if you know. The revised code is below:
def approval_notification(id)
#user = User.find(id)
esign = WickedPdf.new.pdf_from_string(render_to_string pdf: "esign", template: "disclosures/pdfs/esign_pdf.html.erb", formats: :html, encoding: "UTF-8")
attachments['Electronic_Signature.pdf'] = esign
mail(:to => #user.email, :subject => 'Congratulations! You have been approved!')
end

Export MS Word file Rails [duplicate]

How to convert ruby file in word file i.e (docx file). For pdf, we prawn gem. But is there any gem for word file. I am trying to convert my html file in word file so that it can be editable for user too. What should do in that case ? I was planning to convert that file in word file. Will it be possible or not.
If you are using Rails:
in initializers/mime_types.rb:
Mime::Type.register 'application/vnd.ms-word', :msword
in your controller:
say you want to export show action:
def show
#item = Item.find params[:id]
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #item }
format.msword { set_header('msword', "#{#item.title}.doc") }
format.pdf do
render :pdf => 'Coming soon...', :layout => false
end
end
end
define set_header in application_controller.rb:
def set_header(p_type, filename)
case p_type
when 'xls'
headers['Content-Type'] = "application/vnd.ms-excel; charset=UTF-8'"
headers['Content-Disposition'] = "attachment; filename=\"#{filename}\""
headers['Cache-Control'] = ''
when 'msword'
headers['Content-Type'] = "application/vnd.ms-word; charset=UTF-8"
headers['Content-Disposition'] = "attachment; filename=\"#{filename}\""
headers['Cache-Control'] = ''
end
end
now define a show.msword.erb #you can use any template handler like haml etc.
YOUR HTML HERE TO EXPORT TO DOC
AS LIKE NORMAL ERB TEMPLATE
Use htmltoword gem.
https://github.com/nickfrandsen/htmltoword
it hasn't been updated since November 2015, but works well.

Rails and multipart emails with user-defined part selection and html to text autoconversion

Our Rails (3.0.14) application has user profiles where users can choose whether they want to receive HTML formatted emails. To keep things DRY, I would like to only setup one set of templates for all mails (HTML) and then use my own String extension dehtml (basically strip_tags with some formatting modifications) on the text/plain part. Also, I would like to keep the mailer code DRY.
So far, our mailer methods look like this:
def signup_confirmation(user)
#user = user
mail(:to => #user.email, :subject => ..., ...)
end
1. DRY templates: If possible, I would like to avoid having to create 200 additional mail templates, and autocreate the text/plain part from the HTML template. This is the basic idea (dehtml is my own String extension):
def signup_confirmation(user)
#user = user
mail(:to => #user.email, :subject => ..., ...) do |format|
format.html
format.text { render(:file => 'signup_notification.html').dehtml }
end
end
However, this fails with a 'missing template' error. How do I tell Rails to use the HTML template in both cases? I tried appending :formats => :html and :handler => :html but this didn't help.
I don't have a solution here right now. Any ideas?
2: DRY mailer methods:
Since our users should be able to decide whether they want to have HTML or not, the above method will look something like
def signup_confirmation(user)
#user = user
attachments.inline["email-header.jpg"] = File.read(...) if #user.wants_html
mail(:to => #user.email, :subject => ..., ...) do |format|
format.html if #user.wants_html
format.text { render(:file => 'signup_notification.html').dehtml }
end
end
Altogether, this triples the LOC in each method. I would like to DRY this up (since it will have to be inserted into at least 200 mailer methods) as far as possible. One idea would be to write my own mail method (let's call it mymail) as something like
def mymail(user, p={})
attachments.inline["email-header.jpg"] = File.read(...) if user.wants_html
mail(p) do |format|
format.html if user.wants_html
format.text
end
end
(ignoring the above text template problem for now) and then change each call to mail to mymail, as in
def signup_confirmation(user)
#user = user
attachments.inline["email-header.jpg"] = File.read(...) if #user.wants_html
mymail(user, { :to => #user.email, :subject => ..., ... })
end
This works. But is it good practice? Where do I best put mymail - in a helper?
Any insights and recommendations welcome!
I did something very similar to your first solution a long time ago. I don't really remember why it hat to be the way it is, but this is working for me:
def my_mail
mail(:to => #user.email ...) do |format|
format.text { convert_html_to_plain(__method__) } # first text
format.html # then html
end
end
def convert_html_to_plain(method)
old_formats = self.formats
self.formats = ["html"]
rendered = render "#{method}", :layout => false
self.formats = old_formats
# strip tags, reformat, etc. from rendered
rendered << render(:partial => "plaintext_footer", :locals => {:user => #user}, :formats => [:text] )
end

Resources