Mocking fog When Using It With Carrierwave
This post hails from community contributor Mike Gehard from Pivotal Labs. Many thanks to Mike for building on his original article and allowing us to share it with you.
There is a new kid on the block when it comes to file attachments for Rails and it is called Carrierwave. Carrierwave gives you the ability to easily store attachments on S3 (or many other cloud storage providers) using another great gem called fog.
Here is an example of how to set up Carrierwave to use fog as the storage mechanism:
require 'carrierwave/orm/activerecord'
Fog.credentials_path = Rails.root.join('config/fog_credentials.yml')
CarrierWave.configure do |config|
config.fog_credentials = {:provider => 'AWS'}
config.fog_directory = "my-bucket" # required
end
Drop this into a carrierwave.rb initializer file in Rails and away you go.
The contents of the fog_credentials.yml file are standard for a fog credentials file and look like this for S3:
default:
aws_access_key_id: 'XXX' # required
aws_secret_access_key: 'YYY' # required
region: 'us-east-1' # optional, defaults to 'us-east-1'
For more information about fog credential files for different cloud providers, check out the Carrierwave documentation and change the keys/values accordingly.
Uploading files to S3 is great for many reasons but it can slow down your testing environment because it takes a while to send stuff up to S3. The Carrierwave documentation tells you how to switch the storage location over to file storage during testing but that wasn’t enough for me. I wanted to use the same storage mechanism for dev, test and production so I sought out a way to do so.I had heard about fog’s ability to mock itself to pretend that it was interacting with S3 so I decided to see if I could get it working with Carrierwave. This allowed me to use the same storage mechanism in test mode without slowing my tests down waiting for images to go to S3.
After a bunch of tinkering and a message on the fog mailing list (thanks for the quick response Wesley), this is what I came up with:
Fog.mock!
Fog.credentials_path = Rails.root.join('config/fog_credentials.yml')
connection = Fog::Storage.new(:provider => 'AWS')
connection.directories.create(:key => 'my-bucket')
The key is that you have to tell the mocked fog that an S3 bucket exists before it will let Carrierwave put an image there. I wasn’t doing this at first and Carrierwave kept showing me a 404 error from fog. Drop this in a file in your spec/support and/or features/support directories and you will have your tests thinking they are sending things to S3 without actually sending them to S3.
Now I don’t have to mess around with having a bunch of test images laying around my hard drive and I can make sure I’m using the same storage mechanism across all environments without slowing my tests down. Your mileage may vary but I’d love to hear how this works for people and if there are any limitations. I haven’t found any yet.
Author Bio
Mike Gehard lives in Boulder, Colorado and works for Pivotal Labs. At work he’s passionate about test driven development, pair programming, Ruby/Rails and all things Internet. He loves to infect others with his passion for these things. When he’s not at work you can find Mike out in his kayak, on his bike, climbing, or studying philosophy.
Share your thoughts with @engineyard on Twitter