Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit bf82aeea7278a0fb088393ed6721300d3a251d96 @exviva committed May 11, 2012
Showing with 221 additions and 0 deletions.
  1. +5 −0 .gitignore
  2. +4 −0 Gemfile
  3. +22 −0 LICENSE
  4. +154 −0 README.md
  5. +2 −0 Rakefile
  6. +8 −0 lib/paperclip-storage-tmp.rb
  7. +7 −0 lib/paperclip-storage-tmp/version.rb
  8. +19 −0 paperclip-storage-tmp.gemspec
@@ -0,0 +1,5 @@
+/.bundle
+/Gemfile.lock
+/pkg
+/.rvmrc
+/vendor/paperclip
@@ -0,0 +1,4 @@
+source 'https://rubygems.org'
+
+# Specify your gem's dependencies in paperclip-storage-tmp.gemspec
+gemspec
22 LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2012 Olek Janiszewski
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
154 README.md
@@ -0,0 +1,154 @@
+# paperclip-storage-tmp
+
+This gem allows you to configure Paperclip 2.x to use your temporary directory to store the attachments. The attachments are deleted as soon as your Ruby process exits, or whenever you ask the gem to delete them (e.g. after every test), ensuring isolated state for each test.
+
+Thanks to this gem your `public/system` directory is no longer cluttered with attachments dangling in there after your test suite has finished running.
+
+It also prevents the attachments created by tests from conflicting with attachments uploaded in development. Storing the images using the default, `filesystem` storage both in development and test environments may lead to false positives and other unexpected behaviour in your tests.
+
+As an example, imagine you upload an avatar in development. It will probably land in a path similar to `public/system/users/123/avatars/original/hey_mom_its_me.png` (assuming the user's ID is 123). If you feed your application with some kind of fixtures, you probably have hundreds of such files. Now imagine you also have the following test:
+
+ describe User do
+ it 'assigns a default avatar' do
+ user = User.new
+
+ # This method is supposed to assign a default
+ # avatar to the user (called "hey_mom_its_me.png"),
+ # and save the record
+ user.assign_default_avatar!
+
+ # Yikes! False positive alert!
+ user.avatar.should be_present
+ end
+ end
+
+In the test above, `user.avatar.present?` will check if a file `public/system/users/:id/avatars/original/hey_mom_its_me.jpg` exists. That file could as well have been uploaded in development, and even if your method `assign_default_avatar!` is not doing what you expect it to, your test is still passing.
+
+Just like you wouldn't want to use the same database in development and test, you probably don't want to use the same storage directory (which also is a kind of a database).
+
+## Compatibility with Paperclip versions
+
+Please note that this gem has been written with Paperclip 2.x in mind (extracted from and battle-tested in an application dependent on Paperclip 2.4.0). The gemspec declares a rather loose dependency on Paperclip of '~> 2.0', so make sure the gem is behaving as expected. Since it's supposed to be used only in test environment, it shouldn't be harmful to just give it a try. If you confirm that it's working for the version of Paperclip you're using, let me know.
+
+Any pull requests increasing compatibility with other versions welcome!
+
+## Installation
+
+Add this line to your application's Gemfile:
+
+ gem 'paperclip-storage-tmp', group: 'test'
+
+And then execute:
+
+ $ bundle
+
+Or install it yourself as:
+
+ $ gem install paperclip-storage-tmp
+
+## Usage
+
+### Configuring Paperclip to use the temporary storage
+
+To use the tmp storage, simply provide the `:storage` option with the value of `:tmp`, e.g.:
+
+ class User < ActiveRecord::Base
+ has_attached_file :avatar, storage: :tmp
+ end
+
+Unless you're drunk, you probably want to do this conditionally:
+
+ class User < ActiveRecord::Base
+ has_attached_file :avatar, storage: (Rails.env.test? ? :tmp : :filesystem)
+ end
+
+Or use some kind of environment-aware config parameter:
+
+ class User < ActiveRecord::Base
+ has_attached_file :avatar, storage: MyApp.config.paperclip.storage
+ end
+
+If you want to configure this option globally for all attachments, use an initializer:
+
+ # in config/initializers/paperclip.rb
+ Paperclip::Attachment.default_options[:storage] = MyApp.config.paperclip.storage
+
+### Configuring your tests to delete the attachments after every test
+
+The most important part is actually "rolling back the filesystem" after every test, so that the next test will run with isolated state. That's where the `Paperclip::Storage::Tmp.clear` method comes in handy. Call this method in the `teardown`/`after` block of your test framework. Here's an example for `RSpec`:
+
+ # in spec/spec_helper.rb
+ RSpec.configure do |config|
+ config.after do
+ Paperclip::Storage::Tmp.clear
+ end
+ end
+
+## Caveats
+
+Beware that the file name assigned to the model attribute (`<attachment>_file_name`) is different than the name of the assigned/uploaded file (it's the name of the temporary file - a unique string).
+
+Also, Paperclip doesn't know that the file doesn't physically exist in `public/system`, so you can't use `Attachment#path` to access the physical file. You can use `attachment.to_file.path` to find the actual location of the attachment on disk.
+
+Here are a couple of specs, which expose the expected behaviour of this gem. The specs markes with `# FAIL` expose the caveats:
+
+ describe User do
+ describe 'avatar' do
+ let(:user) { User.create!(avatar: File.new('spec/fixtures/hey_mom_its_me.png')) }
+ subject { user.avatar }
+
+ it { should exist }
+ its(:content_type) { should eq('image/png') }
+ its(:original_filename) { should eq('hey_mom_its_me.png') }
+
+ its(:path) { should eq(Rails.root + "/public/system/avatars/1/original/hey_mom_its_me.png") }
+ its(:to_file) { should be_a(File) }
+
+ it 'is actually stored in /tmp' do
+ File.exists?(subject.path).should be_false # FAIL
+ subject.to_file.path.should match(%r{^/tmp/})
+ end
+
+ it 'copies the assigned file' do
+ File.read(subject.to_file).should eq(File.read(avatar_file))
+ end
+
+ it 'stores the file in an imagemagick-friendly way' do
+ geometry = Paperclip::Geometry.from_file(subject.to_file)
+ geometry.width.should eq(256)
+ geometry.height.should eq(256)
+ end
+
+ it 'stores the file attributes in the model' do
+ user.avatar_file_name.should eq('hey_mom_its_me.png')
+ user.avatar_content_type.should eq('image/png')
+ user.avatar_file_size.should eq(File.size(avatar_file))
+ end
+
+ it 'can handle assignment from File' do
+ new_user = User.new(avatar: avatar_file)
+ new_user.avatar_file_name.should eq('hey_mom_its_me.png')
+ end
+
+ it 'can persist assignment from File' do
+ new_user = User.create!(avatar: avatar_file)
+ new_user.reload.avatar_file_name.should eq('hey_mom_its_me.png')
+ end
+
+ # :(
+ it 'cannot handle assignment from Paperclip::Attachment' do
+ new_user = User.new(avatar: subject)
+ new_user.avatar_file_name.should_not eq('hey_mom_its_me.png') # FAIL
+ end
+ end
+ end
+
+## Contributing
+
+In development, the Gemfile points to a version of Paperclip from `vendor/paperclip`, so make sure you have a clone of Paperclip there (e.g. `git clone git://github.com/thoughtbot/paperclip vendor`). You can checkout any version you want to test against.
+
+1. Fork it
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Commit your changes (`git commit -am 'Added some feature'`)
+4. Push to the branch (`git push origin my-new-feature`)
+5. Create new Pull Request
@@ -0,0 +1,2 @@
+#!/usr/bin/env rake
+require "bundler/gem_tasks"
@@ -0,0 +1,8 @@
+require "paperclip-storage-tmp/version"
+
+module Paperclip
+ module Storage
+ module Tmp
+ end
+ end
+end
@@ -0,0 +1,7 @@
+module Paperclip
+ module Storage
+ module Tmp
+ VERSION = "0.0.1"
+ end
+ end
+end
@@ -0,0 +1,19 @@
+# encoding: utf-8
+require File.expand_path('../lib/paperclip-storage-tmp/version', __FILE__)
+
+Gem::Specification.new do |gem|
+ gem.authors = ['Olek Janiszewski']
+ gem.email = ['olek.janiszewski@gmail.com']
+ gem.description = %q{Store Paperclip attachments in your temporary directory}
+ gem.summary = %q{Keep your tests clean by isolating test attachments from development, and between tests}
+ gem.homepage = 'https://github.com/exviva/paperclip-storage-tmp'
+
+ gem.files = `git ls-files`.split($\)
+ gem.test_files = gem.files.grep(%r{^spec/})
+ gem.name = 'paperclip-storage-tmp'
+ gem.require_paths = ['lib']
+ gem.version = Paperclip::Storage::Tmp::VERSION
+
+ gem.add_runtime_dependency 'paperclip', '~> 2.0'
+ gem.add_development_dependency 'rspec'
+end

0 comments on commit bf82aee

Please sign in to comment.