Mocking Multiple CarrierWave Buckets with Fog
At work, I came across the issue of having to deal with having multiple Amazon S3 buckets.
Our file-uploading section of our rails_helper
originally was like the following:
1
2
3
4
Fog.mock!
Fog.credentials_path = Rails.root.join('config/fog_credentials.yml')
connection = Fog::Storage.new(:provider => 'AWS')
connection.directories.create(:key => CarrierWave::Uploader::Base.fog_directory)
New requirements dictated that we were going to make new uploaders to S3, and that they are going to be stored in a different bucket by overriding the fog directory:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class ArticleCSVUploader < CarrierWave::Uploader::Base
storage :fog
include ::CarrierWave::Backgrounder::Delay
def store_dir
"articles/#{model.id}"
end
def extension_white_list
%w(csv)
end
def fog_directory
"news-app-#{Rails.env}"
end
end
Our Article model is as follows:
1
2
3
4
5
class Article < ActiveRecord::Base
attr_accessible :csv
mount_uploader :csv, ArticleCSVUploader
end
We wrote the test for the uploader like so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
require 'rails_helper'
describe ArticleCSVUploader do
after { uploader.remove! }
let(:article) { FactoryGirl.create(:article) }
let(:uploader) { ArticleCSVUploader.new(article) }
describe '#store_dir' do
it 'should just be articles/#{model.id}' do
expect(uploader.store_dir).to eq "articles/#{article.id}"
end
end
describe "with a valid csv" do
let(:csv) { File.open(Rails.root.join('spec', 'fixtures', "some.csv")) }
before do
ArticleCSVUploader.class_eval { storage :file }
uploader.store!(csv);
end
context 'the uploaded csv' do
it "is stored in S3" do
expect(uploader.to_s).to include(article.csv.to_s)
end
end
end
describe "with a filename ending in foo" do
let(:csv) { File.open(Rails.root.join('spec', 'fixtures', "myface.foo")) }
it "won't allow the csv to be uploaded" do
expect { uploader.store!(csv) }.to raise_error(CarrierWave::IntegrityError)
end
end
end
However, running the test gives us an error:
The error here is not as verbose as I would have liked it to have been. It doesn’t say why I was getting the 404
error. However, it does give me an idea which part of the Fog
gem gave the error. I open up the /fog/aws/requests/storage/shared_mock_methods
file and look at put a breakpoint before line 30:
There is no “news-app-test” bucket! Only “exercises-test”. I search for exercises-
in the project and found out that the fog directory is being set in the CarrierWave
configuration file:
1
2
3
4
5
6
7
8
9
10
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS',
aws_access_key_id: 'somekeyid',
aws_secret_access_key: 'somesecretaccesskey',
region: 'us-west-1'
}
config.fog_directory = "exercises-#{Rails.env}"
config.cache_dir = "#{Rails.root}/tmp/uploads"
end
I go back to rails_helper
and inspect CarrierWave::Uploader::Base.fog_directory
:
This gave me the idea of adding the following line:
That got the tests to go all green.
Final words
The lesson that I got here is that sometimes it’s a really good idea to source dive to improve the debugging experience. Sometimes, the error we get is not verbose enough to tell us specifically why something is not working right. Jumping into the innards of an external, traditionally blackbox, library and sprinkling in some debugging statements could give us the next hint that could help us to ultimately solve the problem at hand.