Storing pdfs in Rails app - ruby-on-rails

How would I store a pdf in my Rails app so that users can access/download them?
In my migration, would i i use the datatype t.binary?
Then in my controller/view, how should I present this data?

The answer here is probably it depends. Depends on the size and number of PDFs, where users have to be logged in to view them etc.
If you have lots of large PDFs, its probably not a good idea to store them in the database - just store them on the filesystem and store a file location in the database model.
If you do want to store them in the database, then using a binary column is the way to go.
If users don't have to be logged in to download the PDF's, then you could just place them into the public folder (inside a subfolder) and generate links to them for download - then your controller would only need to generate a link to a static PDF file, and the front end webserver will serve them up automatically without using a Rails process.

I've heard good things about Paperclip, which is a way of transparently handling this stuff - storing files on the filesystem, with a reference to that file location in the database.

This question probably isn't rails specific, but probably best way to do it is to generate the pdf and store them on your filesystem, then in your database keep a record of filenames and a date of when they were created (to delete old ones if you need to).

Related

How to upload and display images on Ruby on Rails without storing them?

I'm making a demo for a ruby gem I created that process images and I have my application for the demo using the gem. I want the demo to allow the user to upload an image and try the demo but I don't really want to store the image in a database.
I read about redis but I'm not sure if is the right solution since I don't think is intended to be used with images.
maybe you could simply ask the user to upload an image address as a string rather than a file?
Storing in Redis is not a bad idea, you could also set an expiry date to delete keys older than x days / hours. But keep in mind that Redis is still a database which you need to maintain.
Another approach is to just store it on the filesystem and delete the oldest file before storing a new one so you only store the latest x files.
http://qnimate.com/storing-binary-data-in-redis/
maybe you could simply ask the user to upload an image address as a string rather than a file?
I like this approach by Hassan, you could ask the user to upload to Dropbox / Google files for instance. Or ask to enter the email address and use Gravatar. This would be a light weight approach so if it's just an example I would go for this.

profile pictures - how to store [duplicate]

This question already has answers here:
Storing Images in DB - Yea or Nay?
(56 answers)
Closed 10 years ago.
in my website, user can upload a profile image.
I wanted to know what is the best way to store those images.
my thought is simply dedicated directory. the image name will be the user_id.
is that a good solution, or there's a smarter one?
You have two options, store the images or use an external source (gravatar).
If you're going to store the images, do you want these images to be publically available or are they private? If they are publically available, then you can store them in your public folder.
You can use something like carrierwave to handle the uploading, versioning and storing of the images.
For public stuff, I'll store the file in the public directory under the uploader/model name/field name/id location. This is more for organizational purposes on my part.
Check out http://railscasts.com/episodes/253-carrierwave-file-uploads for a good tutorial.
For private images, I'll set the store directory to something outside of the public folder and will create a download action within the controller with the file. This way, the user cannot download the file unless it goes through the controller action. With authorization (cancan) I can allow or disallow a user to access the download action for that particular file (hence making it somewhat secure). If you are going to be using a production server like apache or nginx, make sure that you set the appropriate handlers for sending the file (ie x_sendfile).
Its very common to store images in a directory for small applications. However there are a few of things to take into consideration here:
Do you have anticipate a lot of users? If you have a million users, storing everyone's photo in your directory will take up a lot of memory when running your application
Are you deploying on Heroku? Many RoR apps are, and if you deploy on Heroku it will destroy any files you store locally when your app is moved to a different dyno (and you generally have no way of predicting when this will happen). You can read about the Ephemeral filesystem here https://devcenter.heroku.com/articles/dynos#isolation-and-security
In general I would advise against storing all your images locally because rewriting the code as you scale will become painful. I recommend you upload to an Amazon S3 Bucket and download the images as you need (and cache them for when your user is logged in). Its helpful becasue you might have to deal with image processing (for example resizing the images that are uploaded, creating thumbnail versions of the uploaded images) and its easier to do this when you have background processes that have persistent access to these files. I've used the 'aws' gem and S3 libraries for this, and its really easy to use, you can read more about it here: http://amazon.rubyforge.org/
However, if you intend for this to be a small app and are not deploying on Heroku, just saving it to a local directory is a lot easier and pain-free

Mananging upload of images to create custom pdfs on heroku - right tools

Im desiging an app which allows users to upload images (max 500k per image, roughly 20 images) from their hard drive to the site so as to be able to make some custom boardgames (e.g. snakes and ladders) in pdf formate. These will be created with prawn instantly and then made available for instant download.
Neither the images uploaded nor the pdfs created need to be saved on my apps side permanently. The moment the user downloads the pdf they are no longer needed.
Heroku doesn't support saving files to the system (it does allow to the tmp directory but says you shouldnt rely on it striking it out for me). I'm wondering what tools / services I should be looking into to get round this. Ive looked into paperclip, I'm wondering if this is right for this type of job.
Paperclip is on the right track, but the key insight is you need to use the S3 storage backend (Paperclip uses the FS by default which as you've noticed is no good on Heroku). It's pretty handy; instead of flushing writes out to the file system, it uses the AWS::S3 gem to upload them to S3. You can read more about it in the rdoc here: http://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/storage/s3.rb
Here's how the flow would work:
I'd let your users upload their multiple source images. Here's an article on allowing multiple attachments to one model with paperclip: http://www.cordinc.com/blog/2009/04/multiple-attachments-with-vali.html.
Then when you're ready to generate the PDF (probably in a background job, right?), what you do is download all the source images to somewhere in tmp/ (make sure the directory is based on your model id or something so if two people do this at once, the files don't get stepped on). Once you've got all the images downloaded, you can generate your PDF. I know this is using the file system, but as long as you do all your filesystem interactions in one request or job cycle, it will work, your files will still be there. I use this method in a couple production web apps. You can't count on tmp/ being there between requests, but within one it's reliably there.
Storing your generated PDF on S3 with paperclip makes sense too, since then you can just hand your users the S3 URL. If you want you can make something to clear the files off every so often if you don't want to pay the S3 costs, but they should be trivial.
Paperclip sounds like an ideal candidate. It will save images in RAILS_ROOT/public/system/, which is both persistent and private (shouldn't be able to be enumerated on shared hosting).
You can configure it to produce thumbnails of your images if you wish.
And it can remove the images it manages when the associated model is destroyed - after your user downloads their PDF, and you delete the record from the database.
Prawn might not be appropriate, depending on the complexity of the PDFs you need to generate. If you have $$$, go for PrinceXML and the princely gem. I've had some success with wkhtmltopdf, which generates PDFs from a Webkit render of HTML/CSS - but it doesn't support any of the advanced page manipulation stuff that Prince does.

What should my directory structure look like for user assets in a web application?

In my web application, each user will have a logo. I am pretty sure each user will also have a photo gallery in the future. What is the best way to set up a directory structure for managing user logos and possibly other assets such as photos? Also would be good to get people's opinions on what to store in the database. My application is a Rails app.
Just to be clear, this web application will need to scale to possibly hundreds of thousands of users.
There are plugins that offer drop in functionality for the things you're looking to do.
Essentially they work similarly to what Pindatjuh suggests. But you should check out attachment-fu and paperclip to see how the others have done it.
If it's a small web application and you have a database:
One folder containing all avatars (logos). In the database you set the filename of the avatar. Also another folder containing all photo's in a gallery. In the database you have one entry for each asset, pointing to the resource and user.
If it's a bigger, or growing, application, you can automatically create more folders (scripted: each 100 files create a new folder), or even load-balancing by having more than one server solely providing assets.
If you don't have a database:
Create a folder per user, which contains their avatar and assets. This one does not grow, since you don't have a database which points to the user-assets: if you have more than one server, you can't say "which" server the resources are on.

Accessing Word documents in a Rails app

I have a number of documents (mainly Word and Excel) that I'd like to make available to users of my Rails app. However, I've never tried something like this before and was wondering what the best way to do this was? Seeing as there will only be a small number of Word documents, and all will be uploaded by me, do I just store them somewhere in my Rails app (i.e. public/docs or similar) or should I set up a separate FTP and link to that? Perhaps there's an even better way of doing this?
If they're to be publically accessable, you definitely just want to stick them in public somewhere. Write a little helper to generate the URL for you based on however you want to refer to them in your app, for cleanliness (and so if you do change the URL later, for example to bucket your files to keep your directory sizes under control, you don't have to change links all over your app, just in one place.
If, on the other hand, your files are only for logged-in users, you'll need to use something like send_file to do the job, or one of the webserver-specific methods like the X-Sendfile header to check the user is authorised to view the file before sending it back to them.
I would do as you suggested and put them in public/docs. If you are planning on making an overview/index page for the files and link directly to them it would be easier if they were stored locally instead of a remote FTP server. However, since you are the one who will be uploading and maintaining these files, I think you should go with the option that's easiest for you.

Resources