views:

385

answers:

4

I'm using Prawn and Prawnto to generate a PDF in a Ruby on Rails app (Rails version 2.2.2) which works great and generates PDFs happily and sends them to the user to download in Firefox.

The problem is in IE7.

I have a route set up like so:

map.invoice_pdf '/invoices.pdf', :controller => 'invoices', 
                :action => 'index', :format => 'pdf'

Which I then have a link like so to call:

invoice_pdf_path(:year => params[:year], :month => params[:month], 
                 :unpaid_only => params[:unpaid_only])

And the following in my controller:

 def index
    params[:year]  = default params[:year]
    params[:month] = default params[:month]
    params[:page] ||= 1

    @invoices = Arobl.find_invoices_for_customer(current_customer.strCustomerID,
                       params)

    respond_to do |format|
      format.html{ render :action => 'index' }
      format.pdf{
        prawnto :inline => false, :filename => 
                "#{current_customer.strCustomerID}_invoice.pdf"
  end

In FF this works as expected, when the link is clicked the show action is invoked with a format of .pdf, and responds with the correctly named PDF. When it's hit with IE7 it says that the file or website could not be found, and references "invoices.pdf" instead of the expected customer_id_invoice.pdf filename.

Any idea what could be causing this behaviour?

Thanks!

A: 

As an interim solution, I used the approach documented here: http://chelsearobb.wordpress.com/2009/09/09/saving-a-prawn-pdf-to-file/ and just save the file locally, use send_data and a File.read, and then delete the file which seems to work fine in all browsers.

I'm still curious as to why it wouldn't work in IE7 previously though.

fluid_chelsea
+2  A: 

I'm having this problem as well. When I try to request the same PDF without SSL on Internet Explorer (7 or 8) it works, but if I request it with SSL, it doesn't work...

We think we may have tracked this down to headers that IE is expecting when downloading a PDF. I haven't checked the prawnto source code to see what headers it set, but we are likely going to use some Rack Middleware to inject the headers we need:

# add headers for PDF downloads in IE
# PDFs not downloading correctly via SSL in IE
# solution: add some headers for PDF downloads
# http://marc.info/?l=php-general&m=124301243808544&w=2
class RackAddPdfHeadersForIe
  def initialize( app )
    @app = app
  end

  def call( env )
    @status, @headers, @body = @app.call env
    add_headers if is_pdf? and is_internet_explorer?        
    [@status, @headers, @body]
  end

  def is_pdf?
    @headers['Content-Type'] =~ /pdf/
  end

  def is_internet_explorer?
    @headers['User-Agent'] =~ /MSIE ([0-9]{1,}[\.0-9]{0,})/
  end

  def add_headers
    @headers['Content-Description'] = 'File Transfer'
    @headers['Content-Transfer-Encoding'] = 'binary'
    @headers['Expires'] = '0'
    @headers['Pragma'] = 'public'
  end      
end

So I tried this, thought it would work, then found that indeed it still didn't work.

So I ended up doing this, for whatever reason, this worked for me:

class ReportsController < ApplicationController

  def payroll_summary
    respond_to do |format|
      format.pdf do 
        response.headers['Content-Disposition'] = "attachment;filename=\"#{action_name}.pdf\""
        response.headers['Content-Description'] = 'File Transfer'
        response.headers['Content-Transfer-Encoding'] = 'binary'
        response.headers['Expires'] = '0'
        response.headers['Pragma'] = 'public'
        render
      end  #format.pdf
    end #respond_to
  end #payroll_summary

end
Jeff Wigal
If I ever get a chance to revisit that code I will definitely give this a shot, thanks!
fluid_chelsea
This doesn't seem to do the trick for me unfortunately. :(
Steve
I modified my original post to what we're currently using in production. This seemed to work for us...
Jeff Wigal
Setting headers: WorksForMe.
wesgarrison
A: 

I put Jeffs code into a small gem, find it at http://github.com/tobmatth/rack-add-pdf-headers-for-ie

A: 

This ie issue is explained in http://support.microsoft.com/kb/323308

The solution is to set your Cache-Control header to something other than no-store with something like:

response.headers["Cache-Control"] = "private, max-age=0, must-revalidate"

More people are likely to run into this as rails 2.3.6+ seems to set Cache-Control to no-store where earlier versions didn't.

James Healy