While we were working on speeding the run time of our specs, it came to our attention that the [Paperclip](https://github.com/thoughtbot/paperclip) gem contributes a fair amount to the slowness of the specs, mainly because of its dependency on external software like ImageMagick's [convert](http://www.imagemagick.org/script/convert.php) and [identify](http://www.imagemagick.org/script/identify.php); and Unix's [file](https://en.wikipedia.org/wiki/File_%28command%29). Shelling-out may not be this slow, but when done a lot, it starts to have a visible effect. After digging into Paperclip source code, we came up with some fixes that worked well for us. Let's get started.
This is an easy one, yet it wasn't this straightforward to find. Paperclip depends on cocaine gem to run the aforementioned commands. cocaine supports multiple strategies for how to run commands, from which it chooses the best strategy to use on the running platform. Our gemset didn't have posix-spawn installed, so cocaine uses the next best strategy, which is to use Process.spawn. posix-spawn gem provides a spawn method as well, so in order to know the difference between each we quote posix-spawn's README:
fork(2) calls slow down as the parent process uses more memory due to the need to copy page tables. In many common uses of fork(), where it is followed by one of the exec family of functions to spawn child processes (Kernel#system, IO::popen, Process::spawn, etc.), it's possible to remove this overhead by using special process spawning interfaces (posix_spawn(), vfork(), etc.)
As part of creating thumbnails out of the original attached file, Paperclip checks if the original file is an animated file. Currently, the only format recognized as animated is GIF, but other formats can be added in the future. But this future hasn't arrived since mid-2011, so for the time being, we can assume it will only be GIF files that are checked. Checking is done using ImageMagick's `identify` command, and we already established that we want to minimize our shelling-out. It turns out that checking if a file is GIF or not can be done easily by simply reading the first six bytes of the file and comparing it to either "GIF87a" or "GIF89a" (the magic numbers of GIF files).
So we monkey-patch Paperclip::Thumbnail class like this (e.g. in an initializer):
This one is a bit subjective. In the case of our specs, we don't care for the generation of the thumbnails of the attached images, so why bother running commands like convert or identify if we're gonna delete the resulting thumbnails by the end of the suite run?
So we add this snippet to our spec_helper.rb or to a support file that's required by spec_helper.rb:
Applying these methods saved us about five minutes in test running time, which is definitely an improvement.
NOW IT'S YOUR TURN: How have you optimized Paperclip Gem? Let us know in the comments below.