Welcome to Working With Rails

 

Discussion Forums

Discuss all things Ruby on Rails with perhaps the web's most vibrant group of Ruby on Rails enthusiasts.
Send dynamicly generated pdf as attachement
11 Posts
Send dynamicly generated pdf as attachement

Austin, Thanks to the start you gave me, I've managed to get this working today:

Here's the code from my model that generates a PDF from a Prawnto view and saves it to a file:

av = ActionView::Base.new(Rails::Configuration.new.view_path)
av.extend ApplicationController.master_helper_module
av.controller = ActionController::Base.new
av.controller.request = ActionController::Request.new({ "SERVER_PROTOCOL" => "", "REQUEST_URI" => "", "action_controller.request.request_parameters" => {:format => :pdf} })
av.controller.response = ActionController::Response.new
av.controller.headers = Rack::Utils::HeaderHash.new
av.controller.prawnto :prawn => { :page_size      => 'A4' } # your Prawto settings here....
pdf = Prawn::Document.new(av.controller.instance_variable_get(:@prawnto_options)[:prawn])
pdf_body = av.render(:file => 'reports/render_me.pdf.prawn', :locals => {:pdf => pdf}, :layout => false )
File.open("MGPtest", 'w') {|f| f.write(pdf_body) }

This is a first draft of a working version, so can probably be cleaned up a litte (or lot!).

Of course, YMMV, and this is a total cludge of the MVC principles - but sometimes you've just got to...

Hope this helps out there.

Austin,

I didn't manage to fix this problem, I keep sending the mails in plain text rather than in pdf.

Wouter,

Have you ever managed to get this working? I'm attempting to do the same thing. Basically what I want to do is have my model access the prawn pdf so I can easily attach the file when I send the email out. I found that you do it from the controller using: @output = render_to_string :template => 'invoices/show.pdf.prawn', :layout => false

But apparently you can't use render_to_string in the model or in a rake task. For a model and rake task I found these articles http://www.compulsivoco.com/2008/10/rendering-rails-partials-in-a-model-or-background-task/ http://www.gregorydoran.co.uk/2009/08/ruby-on-rails-rendering-views-outside-of-the-controller/ http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/14f5f3f6f7819d27

following those I figured in my Invoice Model I could do something like this

def pdf_file

av = ActionView::Base.new(Rails::Configuration.new.view_path)
av.extend ApplicationController.master_helper_module 
output = av.render(
  :file => 'invoices/show.pdf.prawn',
  :locals => {:invoice => self},
  :layout => false 
)

end

My ideas was in my mailer I could attach the file using something like this.

def test(user, invoice)

recipients    user.email
from          "Testing "
subject       "Email Testing"
body          :user => user
content_type "text/html"
attachment "application/pdf" do |a|
  a.body = invoice.pdf_file
end

end

But in the end I'm stuck with a weird prawn error

ActionView::TemplateError: ActionView::TemplateError (You have a nil object when you didn't expect it! The error occurred while evaluating nil.compute_prawnto_options) on line #1 of app/views/invoices/show.pdf.prawn: 1: pdf.text "Invoice ##{@invoice.id}", :size => 30, :style => :bold 2: pdf.text "#{@invoice.user.firstname} #{@invoice.user.lastname}", :size => 20 3: pdf.text "#{@invoice.user.address1}", :size => 20 ......

I know I'm not offering any solution but maybe some of this might point you into the right direction. Let me know if you ever get it working.

Thanks Sonny, that's working fine but the problem is that I have 200 and more lines of code for generating the pdf and I'd like to keep it out of my controller so that it can stay clean. Isn't there a way to render some kind of template ( a .pdf.prawn) and include that in my Notifier.deliver methode?

Hi Wouter,

How about this?

In your controller, you generate the PDF file:

Prawn::Document.new do      
    text "THIS IS A PDF"
end.render

Notifier.deliver_signup_notification(customer_email, pdf_file)

In your notifier action mailer:

def signup_notification(customer_email, pdf_file)
    @from         = "example@email.com"
    @recipients   = customer_email
    @subject      = "Reactie"
    @sent_on      = Time.now
    @content_type = "text/html"

    attachment :content_type => "application/octet-stream", :filename => "your_file_name_here.pdf", :body => pdf_file    
end

Hope that helps. Something wrong with format here, so I paste the code in "here":http://pastie.org/554806

Sonny

I'm sorry for my late response, I had some last exams.

On topic :

I've tried to generate a pdf in my controller (that didn't go so fine), but recently I found this site (http://dizzy.co.uk/ruby_on_rails/cheatsheets/action-mailer#multipart_messages), and I quote

ActionMailer will automatically detect and use multipart templates, where each template is named after the name of the method, followed by the content type. Each such detected template will be added as a separate part to the message. For example:

signup_notification.text.plain.erb signup_notification.text.html.erb signup_notification.text.xml.builder

Each would be rendered and added as a separate part to the message with the corresponding content type. The same body hash is passed to each template.

So in my notifier view folder I created a send_mail.html.erb template and a send_mail.pdf.prawn, but when I send the email, the pdf attachement isn't added.

Could anyone tell me if this info is correct and what I'm doing wrong? http://pastie.org/551464

You do not need the real PDF file as attachment. Actually, only the generated content (binary stream) of this pdf document is necessary. You can access to this stream via response object. Your codes of controller should looks like the following:

def show # just a example
  render # force to generate pdf using prawnto so we can access to the response object
  pdf = response.body
  YourMailer.deliver_generated_pdf(current_user, pdf)
end

You can move the logic that creates the pdf from the .prawn file to your controller or even better to a model. You will want to use pdf = Prawn::Document.new and the render method to create a string version of the pdf which can be attached to the email.

Check out http://prawn.majesticseacreature.com/docs/prawn-core/classes/Prawn/Document.html#M000097 and http://prawn.majesticseacreature.com/docs/prawn-core/classes/Prawn/Document.html#M000101.

And how can I then generate the pdf document? Like the railscast, I just had to create a .pdf.prawn document and that's it.

Refer to Rails API of ActionMailer::Base about sending mails with attachments. According to the document that you could just pass the content of generated PDF as params of the mailer class, looks like this:

def generated_pdf(recipient, pdf)
  attachment "application/pdf" { |a| a.body = pdf }
end

FYI, to get the content of generated PDF, the "render_as_string" method and read the response.body after rendering automatically will be both useful in this situation.

11 Posts
Login to add your message