madcow madcow - 2 months ago 11x
Ruby Question

Stubbing Paperclip downloads from S3 in RSpec

I am using Paperclip/RSpec and StackOverflow has helped me successfully stub file uploads to S3 using this code:


config.before(:each) do
allow_any_instance_of(Paperclip::Attachment).to receive(:save).and_return(true)

This is working great.

On my model I have two Paperclip fields:

class MyModel < ActiveRecord::Base
has_attached_file :pdf
has_attached_file :resource

My code uses the
#copy_to_local_file method
to retrieve a file from S3.

takes two params: the style (
, etc) and the local file path to copy to.


MyModel.resource.copy_to_local_file(:original, local_file.path)

When the system under test tries to access
, I originally got errors like the following:

No Such Key - cannot copy /email_receipts/pdfs/000/000/001/original/email_receipt.eml.pdf to local file /var/folders/4p/1mm86g0n58x7d9rvpy88_s9h0000gn/T/receipt20150917-4906-13evk95.pdf
No Such Key - cannot copy /email_receipts/resources/000/000/001/original/email_receipt.eml to local file /var/folders/4p/1mm86g0n58x7d9rvpy88_s9h0000gn/T/resource20150917-4906-1ysbwr3.eml

I realize these errors were happening because uploads to S3 are stubbed, so when it encounters
it tries to grab a file in S3 that isn't there.

Current Solution:

I've managed to quash the errors above, but I feel it's not a complete solution and gives my tests a false sense of security. My half-solution is to stub this method in the following way:


before(:each) do
allow_any_instance_of(Paperclip::Storage::S3).to receive(:copy_to_local_file)

While this does stub out the
method and removes the errors, it doesn't actually write any content to the local file that is provided as the second argument to
, so it doesn't quite simulate the file being downloaded from S3.


Is there a way to stub
AND have it write the contents of a canned file in my
directory to the local file (its second argument)?

Or am I overthinking this? Is this something I shouldn't be worrying about?


You don't need to worry about whether the 'downloaded' files actually exist in your tests. You've decided to stub out Paperclip, so do it completely, by stubbing out both #save and #copy_to_file. You may also need to stub out reads of downloaded files from the filesystem.

All this stubbing raises the possibility of integration errors, so you should probably write a feature spec (using a captive browser like poltergeist) that actually uploads and downloads something and reads it from the filesystem.

That said, you can do anything you want in an RSpec stub by passing it a block:

allow_any_instance_of(Paperclip::Storage::S3).to receive(:copy_to_local_file) do |style, local_dest_path|
  # write a file here, or do anything you like