44

I have looked around on the internet, but do not seem able to find how to display a PDF in rails (I can only find info on how to create one).

Does anyone know what code/gem I need to display one?

Benoit Garret
  • 14,027
  • 4
  • 59
  • 64
IAmGroot
  • 13,760
  • 18
  • 84
  • 154
  • Use [prawn](https://github.com/sandal/prawn) is a sort of de-facto standard. – lucapette Sep 21 '11 at 13:27
  • 4
    The hall monitors strike again. As of today 29 of us think this is a good question and 1 know it all says it's not but somehow had the authority to close it. SO is broken. – user1130176 Aug 31 '18 at 11:06

5 Answers5

56

In your controller:

def pdf
  pdf_filename = File.join(Rails.root, "tmp/my_document.pdf")
  send_file(pdf_filename, :filename => "your_document.pdf", :type => "application/pdf")
end

In config/environment/production.rb:

config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache

or

config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx

The config modification is required because it enables the web server to send the file directly from the disk, which gives a nice performance boost.

Update

If you want to display it instead of downloading it, use the :disposition option of send_file:

send_file(pdf_filename, :filename => "your_document.pdf", :disposition => 'inline', :type => "application/pdf")

If you want to display it inline, this question will be much more complete that I could ever be.

Community
  • 1
  • 1
Benoit Garret
  • 14,027
  • 4
  • 59
  • 64
  • Hey this is great stuff. In terms of sending a pdf to the user. But what about displaying it on the website, before sending it ? :) – IAmGroot Sep 21 '11 at 14:20
  • Looks like my answer doesn't satisfy you, could you tell me why? – Benoit Garret Sep 22 '11 at 11:09
  • sorry yes. Briefly adding the dispoition still wanted the user to download it. I havent added the iframe, but an example would be great on how to load a pdf inside such. :). I finished working yesterday not long after your reply, and was pre-engaged with a bug on other software since. Ive only very recently managed to successfully recieve the pdf over my webservice uncorrupted. – IAmGroot Sep 22 '11 at 12:06
  • Think ill stick to the easy, already implemented idea. for which you helped me with. thanks – IAmGroot Sep 22 '11 at 13:28
  • @BenoitGarret sorry for bother you, but, looks like `File.join(Rails.root, "tmp/my_document.pdf")` returns a string with the absolute path, for example: `/home/user/rubyprojects/proj/assets/file.pdf`, so, if it is an asset and i put 'assets/file.pdf' as the second parameter, It doesn't resolve it. How could i achieve that? Great answer by the way. – JGutierrezC Dec 10 '13 at 22:37
  • @JGutierrezC The path is relative to the project root, does it work with `File.join(Rails.root, "app/assets/file.pdf")`? – Benoit Garret Dec 11 '13 at 13:14
  • @BenoitGarret it works. But the path is `/home/user/...`, i think i didn't explain myself, my question is, shouldn't it be looking for `http://127.0.0.1:3000/assets/file.pdf` instead of a local folder? Thanks in advance man – JGutierrezC Dec 11 '13 at 14:44
  • @JGutierrezC The sendfile header tells your web server to look for the file locally and send it directly to the client. You don't send the url to the client. This allows you to serve files even though they're not available in a public folder. – Benoit Garret Dec 11 '13 at 16:25
  • 2
    This did it for me: `send_file(..., disposition: 'inline')` – Benjamin Crouzier Sep 18 '16 at 18:58
9

Basically you just need to write it in the html in your view. So this simple solution worked for me:

In the 'show.hmtl.erb'

<iframe src=<%= @certificate.certificate_pdf %> width="600" height="780" style="border: none;"> </iframe>

just putting the file location in embedded ruby as the source of the iframe tag worked for me after hours and hours of searching. 'certificate' is my model, and 'certificate_pdf' is my attachment file.

andrewcockerham
  • 2,676
  • 3
  • 23
  • 19
  • this worked for me. using `send_file(..., disposition: 'inline')` plus using the route which generates the pdf will show pdf in iframe. – Junaid Atique May 14 '19 at 09:36
3

Depending where the PDF comes from, the following may help you. I have an application where I store a lot of things, and some of them have (additional) PDFs connected to the items. I store the items in the directory /public/res/<item_id>/. res means result, and item_id is the numeric id of that item in Rails.

In the view, I provide a link to the PDFs by the following (pseudo-)code as a helper method, that may be used in the view:

def file_link(key, name = nil)
  res= Ressource.find(:first, :conditions => ["key = ?", key])
  list = Dir["public/res/#{res.id}/*"]
  file= list.empty? ? "" : list[0]
  return file if file.empty?
  fn = name ? name : File.basename(file)
  link_to fn, "/res/#{res.id}/#{File.basename(file)}", :popup => true
end

The relevant part here is the link_to name, "/res/#{res.id}/#{File.basename(file)}" thing.

mliebelt
  • 15,345
  • 7
  • 55
  • 92
  • Two things to note about your solution: 1/ you can only display files that are in the `public` folder. 2/ You cannot change the name of the file in the browser save dialog. – Benoit Garret Sep 21 '11 at 13:51
  • That is true, but sometimes sufficient. Its a simple solution, I know :-) – mliebelt Sep 21 '11 at 13:54
  • 1
    You're perfectly right, I just wanted to point out the restrictions which may (or not ;-) ) be deal-breakers. – Benoit Garret Sep 21 '11 at 13:56
2

This may be too simple, but I had trouble finding a simple answer to my problem, so I'm posting it here. I really didn't want to add another action to my controller just to download a static file.

I just uploaded my file to S3 & used link_to referring to the path, which S3 provides after you upload the file and set the permissions (remember, everyone has to be able to upload and download it). I store lots of data for the app on S3 so it seemed like a fine choice.

<%= link_to "speaker registration form", "https://s3.amazonaws.com/gws_documents/speaker_registration.pdf" %>
Makean
  • 71
  • 5
1
def pdf
  pdf_content = ...# create the pdf
  send_data(pdf_content, :filename => "test.pdf", :type => "application/pdf")
end
Matt
  • 17,290
  • 7
  • 57
  • 71