CarrierWave has an awesome abstraction API. It is simple, clear and extensible. But has some critical vulnerability specially when combined with image processing, such as, ImageMagick when resizing an image will consume exponencial memory size and any upload can easily make your process crash, when not processed safely. Also, it is not pretty good to combine .gif out of the box, because it makes a collection out of the file.
Friendly advice beforehand; Using http://filepicker.io/ may be a way better idea if you are hosting in Heroku, just make sure if fits your constraints before get hard work done.
Hard limit file size of the request, so the process don’t block for too long, and don’t blow memory!
If you behind a server such as Apache or Nginx, you can impose a limit to the request size, and you should!
Unless you are in Heroku, and afaik, there is no way to do that, at least just yet. So yes, this can be a major security breach for Rails apps on Heroku.
Given a successful upload, pre-validate size.
The ‘official’ solution attempt to validate the size after the file have been processed. It doesn’t help, since when processing an image rather large (6Mb image consumed 2GB memory in my case) your process will be killed! Letting your website down for some time, and letting your users down as well.
For gifs, take only the first image (less memory consumption too)
When processing .gifs it seems to make a vertical frameset will all the images in the sequence, so it looks like a movie roll, which is not what most people want. Lets just extract the first frame.
Interestingly enough, I found that the processor is invoked for all frames in the .gif. (thanks debugger!)
This code takes care the mentioned specs (except for the request size limit), and I think the great advantage is that it avoids opening a file as Image if it fails the size constraint. As well as being very efficient with gifs (only acting on the first frame).
It works on Heroku, with integration for S3, and should work on Amazon Cloud and other VPS.
The shortcome is about handling the exception which is a bit messy involving controller-side logic in a non-automated AR fashion.
@post = Post.new(params[:post])
rescue Exception => e
if e.message == 'too large'
redirect_to news_path(err: 'file')
# encoding: utf-8
class NewsUploader < CarrierWave::Uploader::Base
def pre_limit file
#require 'debugger'; debugger
if file && file.size > 5.megabytes
raise Exception.new("too large")
manipulate! do |img|
if img.mime_type.match /gif/
if img.scene == 0
img = img.cur_image #Magick::ImageList.new( img.base_filename )
img = nil # avoid concat all frames
version :large, if: :pre_limit do
process :convert => 'jpg'
process :resize_to_limit => [1280, 1024]
# Create different versions of your uploaded files:
version :small, if: :pre_limit do
process :convert => 'jpg'
process :resize_to_limit => [360, 360]
# For images you might use something like this:
%w(jpg jpeg gif png)