Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Replace aws-s3 storage backend with the AWS SDK for Ruby. #579

Closed
wants to merge 5 commits into from

9 participants

mattyn Kevin Elliott Maurício Linhares louis cuny James Cropcho Mike Burns Prem Sichanugrist Igor Alexandrov Trevor Rowe
mattyn

This commit replaces aws-s3 as the backend for storing uploaded files in Amazon S3 with the aws-sdk gem, which is the official AWS SDK for Ruby. The new backend supports all of the same options as the original one, with two additions:

  • :s3_metadata -- Automatically adds the "x-amz-meta-" prefix to the keys in the hash.
  • :s3_storage_class -- Equivalent to passing "x-amz-storage-class" in :s3_headers.

We've updated the unit tests to do mocking and stubbing against the aws-sdk API, but we left the integration tests alone. We were able to get all of the tests to pass under each of the appraisals, including the integration tests.

A significant side effect of this patch is that it is no longer possible to use aws-s3 in the same application as paperclip, because both aws-s3 and aws-sdk use the AWS::S3 constant in incompatible ways.

Kevin Elliott

I have used this branch, and it works as advertised. I appreciate being on the official aws-sdk gem, and it takes advantage of newer official APIs, such as copying between buckets on S3 without first downloading the content to wherever the gem is running from which is useful for executing in rake tasks.

I did experience an incompatibility with trying to specify paperclip options in my config/environments/development.rb since this branch is based on 2.3.x to which I've not yet figured out a solution. But otherwise, I would love to see this pull request merged in officially!

Paperclip.options[:command_path] = '/opt/local/bin/'

config/environments/development.rb:19:in load_environment': undefined methodoptions' for Paperclip:Module (NoMethodError)

Cheers,
Kevin

Maurício Linhares

Plus one here, I started to write code for it myself and now I don't have to do it anymore, thanks @kevinelliott :)

Kevin Elliott

@mauricio, thanks for the note, but the real thanks should go to @mattyn who opened this pull request (and I assume likely did all the hard work). And another person who gives +1 adds to the demand for getting this into master... thanks for that!

louis cuny

+1 for merging this in master. I'm currently using the amazonwebservices fork in production.

Mike Burns
Admin

This pull request cannot be automatically merged anymore. The only tricky file is lib/paperclip/storage/s3.rb. Can you rebase this pull request and then we'll pull it in?

Thanks,
-Mike

trevorrowe added some commits
Trevor Rowe trevorrowe Merge remote branch 'thoughtbot/master' into aws-sdk-backend
Conflicts:
	Gemfile
	Gemfile.lock
	features/support/s3.rb
	gemfiles/rails2.gemfile
	gemfiles/rails2.gemfile.lock
	gemfiles/rails3.gemfile
	gemfiles/rails3.gemfile.lock
	gemfiles/rails3_1.gemfile
	gemfiles/rails3_1.gemfile.lock
	lib/paperclip/storage/s3.rb
	test/storage/s3_test.rb
5f5369d
Trevor Rowe trevorrowe fixed tests for the s3 storage 1f93b89
Trevor Rowe trevorrowe raising appropriate error for missing :bucket option 19c1ad7
Prem Sichanugrist
Admin

I actually would love to see aws-sdk as another storage option to retain backward compatibility. If people switch to aws-sdk a lot, then we going to make it as default.

Mike Burns
Admin
% ruby -v
ruby 1.8.7 (2011-02-18 patchlevel 334) [x86_64-linux]
% bundle && rake && git push
Fetching source index for http://rubygems.org/
Using rake (0.9.2) 
Using multi_json (1.0.3) 
Using activesupport (3.1.1) 
Using builder (3.0.0) 
Using i18n (0.6.0) 
Using activemodel (3.1.1) 
Using arel (2.2.1) 
Using tzinfo (0.3.30) 
Using activerecord (3.1.1) 
Using bundler (1.0.12) 
Using appraisal (0.3.8) 
Using rack (1.3.5) 
Using bcat (0.6.2) 
Using ffi (1.0.9) 
Using childprocess (0.2.2) 
Using diff-lcs (1.1.3) 
Using json (1.6.1) 
Using gherkin (2.4.21) 
Using term-ansicolor (1.0.7) 
Using cucumber (1.0.6) 
Using rdiscount (1.6.8) 
Using rspec-core (2.7.1) 
Using rspec-expectations (2.7.0) 
Using rspec-mocks (2.7.0) 
Using rspec (2.7.0) 
Using aruba (0.4.6) 
Installing multi_xml (0.4.1) 
Installing httparty (0.8.1) 
Using nokogiri (1.5.0) 
Installing uuidtools (2.1.2) 
Installing aws-sdk (1.2.1) 
Using mime-types (1.16) 
Using rack-test (0.6.1) 
Using json_pure (1.6.1) 
Using rubyzip (0.9.4) 
Using selenium-webdriver (2.9.0) 
Using xpath (0.1.4) 
Using capybara (1.1.1) 
Using cocaine (0.2.0) 
Using coderay (0.9.8) 
Using excon (0.7.6) 
Using fakeweb (1.3.0) 
Using formatador (0.2.1) 
Using net-ssh (2.1.4) 
Using net-scp (1.0.4) 
Using ruby-hmac (0.4.0) 
Using fog (1.0.0) 
Using metaclass (0.0.1) 
Using sexp_processor (3.0.7) 
Using ruby_parser (2.0.6) 
Using method_source (0.6.6) 
Using mocha (0.10.0) 
Using slop (2.1.0) 
Using pry (0.9.6.2) 
Using rdoc (3.11) 
Using shoulda (2.11.3) 
Using sqlite3 (1.3.4) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
>> bundle install --gemfile=/home/mike/lib/paperclip/gemfiles/rails2.gemfile
Using rake (0.9.2) 
Using activesupport (2.3.14) 
Using rack (1.1.2) 
Using actionpack (2.3.14) 
Using actionmailer (2.3.14) 
Using activerecord (2.3.14) 
Using activeresource (2.3.14) 
Using bundler (1.0.12) 
Using appraisal (0.3.8) 
Using bcat (0.6.2) 
Using ffi (1.0.9) 
Using childprocess (0.2.2) 
Using builder (3.0.0) 
Using diff-lcs (1.1.3) 
Using json (1.6.1) 
Using gherkin (2.4.21) 
Using term-ansicolor (1.0.7) 
Using cucumber (1.0.6) 
Using rdiscount (1.6.8) 
Using rspec-core (2.7.1) 
Using rspec-expectations (2.7.0) 
Using rspec-mocks (2.7.0) 
Using rspec (2.7.0) 
Using aruba (0.4.6) 
Using multi_json (1.0.3) 
Using multi_xml (0.4.1) 
Using httparty (0.8.1) 
Using nokogiri (1.5.0) 
Using uuidtools (2.1.2) 
Using aws-sdk (1.2.1) 
Using mime-types (1.16) 
Using rack-test (0.6.1) 
Using json_pure (1.6.1) 
Using rubyzip (0.9.4) 
Using selenium-webdriver (2.9.0) 
Using xpath (0.1.4) 
Using capybara (1.1.1) 
Using cocaine (0.2.0) 
Using coderay (0.9.8) 
Using excon (0.7.6) 
Using fakeweb (1.3.0) 
Using formatador (0.2.1) 
Using net-ssh (2.1.4) 
Using net-scp (1.0.4) 
Using ruby-hmac (0.4.0) 
Using fog (1.0.0) 
Using metaclass (0.0.1) 
Using sexp_processor (3.0.7) 
Using ruby_parser (2.0.6) 
Using method_source (0.6.6) 
Using mocha (0.10.0) 
Using paperclip (2.4.4) from source at ../ 
Using slop (2.1.0) 
Using pry (0.9.6.2) 
Using rails (2.3.14) 
Using rdoc (3.11) 
Using shoulda (2.11.3) 
Using sqlite3 (1.3.4) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
>> bundle install --gemfile=/home/mike/lib/paperclip/gemfiles/rails3.gemfile
Using rake (0.9.2) 
Using abstract (1.0.0) 
Using activesupport (3.0.10) 
Using builder (2.1.2) 
Using i18n (0.5.0) 
Using activemodel (3.0.10) 
Using erubis (2.6.6) 
Using rack (1.2.4) 
Using rack-mount (0.6.14) 
Using rack-test (0.5.7) 
Using tzinfo (0.3.30) 
Using actionpack (3.0.10) 
Using mime-types (1.16) 
Using polyglot (0.3.2) 
Using treetop (1.4.10) 
Using mail (2.2.19) 
Using actionmailer (3.0.10) 
Using arel (2.0.10) 
Using activerecord (3.0.10) 
Using activeresource (3.0.10) 
Using bundler (1.0.12) 
Using appraisal (0.3.8) 
Using bcat (0.6.2) 
Using ffi (1.0.9) 
Using childprocess (0.2.2) 
Using diff-lcs (1.1.3) 
Using json (1.6.1) 
Using gherkin (2.4.21) 
Using term-ansicolor (1.0.7) 
Using cucumber (1.0.6) 
Using rdiscount (1.6.8) 
Using rspec-core (2.7.1) 
Using rspec-expectations (2.7.0) 
Using rspec-mocks (2.7.0) 
Using rspec (2.7.0) 
Using aruba (0.4.6) 
Using multi_json (1.0.3) 
Using multi_xml (0.4.1) 
Using httparty (0.8.1) 
Using nokogiri (1.5.0) 
Using uuidtools (2.1.2) 
Using aws-sdk (1.2.1) 
Using json_pure (1.6.1) 
Using rubyzip (0.9.4) 
Using selenium-webdriver (2.9.0) 
Using xpath (0.1.4) 
Using capybara (1.1.1) 
Using cocaine (0.2.0) 
Using coderay (0.9.8) 
Using excon (0.7.6) 
Using fakeweb (1.3.0) 
Using formatador (0.2.1) 
Using net-ssh (2.1.4) 
Using net-scp (1.0.4) 
Using ruby-hmac (0.4.0) 
Using fog (1.0.0) 
Using metaclass (0.0.1) 
Using sexp_processor (3.0.7) 
Using ruby_parser (2.0.6) 
Using method_source (0.6.6) 
Using mocha (0.10.0) 
Using paperclip (2.4.4) from source at ../ 
Using slop (2.1.0) 
Using pry (0.9.6.2) 
Using rdoc (3.11) 
Using thor (0.14.6) 
Using railties (3.0.10) 
Using rails (3.0.10) 
Using shoulda (2.11.3) 
Using sqlite3 (1.3.4) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
>> bundle install --gemfile=/home/mike/lib/paperclip/gemfiles/rails3_1.gemfile
Using rake (0.9.2) 
Using multi_json (1.0.3) 
Using activesupport (3.1.1) 
Using builder (3.0.0) 
Using i18n (0.6.0) 
Using activemodel (3.1.1) 
Using erubis (2.7.0) 
Using rack (1.3.5) 
Using rack-cache (1.1) 
Using rack-mount (0.8.3) 
Using rack-test (0.6.1) 
Using hike (1.2.1) 
Using tilt (1.3.3) 
Using sprockets (2.0.3) 
Using actionpack (3.1.1) 
Using mime-types (1.16) 
Using polyglot (0.3.2) 
Using treetop (1.4.10) 
Using mail (2.3.0) 
Using actionmailer (3.1.1) 
Using arel (2.2.1) 
Using tzinfo (0.3.30) 
Using activerecord (3.1.1) 
Using activeresource (3.1.1) 
Using bundler (1.0.12) 
Using appraisal (0.3.8) 
Using bcat (0.6.2) 
Using ffi (1.0.9) 
Using childprocess (0.2.2) 
Using diff-lcs (1.1.3) 
Using json (1.6.1) 
Using gherkin (2.4.21) 
Using term-ansicolor (1.0.7) 
Using cucumber (1.0.6) 
Using rdiscount (1.6.8) 
Using rspec-core (2.7.1) 
Using rspec-expectations (2.7.0) 
Using rspec-mocks (2.7.0) 
Using rspec (2.7.0) 
Using aruba (0.4.6) 
Using multi_xml (0.4.1) 
Using httparty (0.8.1) 
Using nokogiri (1.5.0) 
Using uuidtools (2.1.2) 
Using aws-sdk (1.2.1) 
Using json_pure (1.6.1) 
Using rubyzip (0.9.4) 
Using selenium-webdriver (2.9.0) 
Using xpath (0.1.4) 
Using capybara (1.1.1) 
Using cocaine (0.2.0) 
Using coderay (0.9.8) 
Using excon (0.7.6) 
Using fakeweb (1.3.0) 
Using formatador (0.2.1) 
Using net-ssh (2.1.4) 
Using net-scp (1.0.4) 
Using ruby-hmac (0.4.0) 
Using fog (1.0.0) 
Using metaclass (0.0.1) 
Using sexp_processor (3.0.7) 
Using ruby_parser (2.0.6) 
Using method_source (0.6.6) 
Using mocha (0.10.0) 
Using paperclip (2.4.4) from source at ../ 
Using slop (2.1.0) 
Using pry (0.9.6.2) 
Using rack-ssl (1.3.2) 
Using rdoc (3.11) 
Using thor (0.14.6) 
Using railties (3.1.1) 
Using rails (3.1.1) 
Using shoulda (2.11.3) 
Using sqlite3 (1.3.4) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
>> BUNDLE_GEMFILE=/home/mike/lib/paperclip/gemfiles/rails2.gemfile bundle exec /var/lib/gems/1.8/bin/rake test cucumber
/usr/bin/ruby1.8 -I"lib:lib:profile" -I"/var/lib/gems/1.8/gems/rake-0.9.2/lib" "/var/lib/gems/1.8/gems/rake-0.9.2/lib/rake/rake_test_loader.rb" "test/**/*_test.rb" 
Testing against version 2.3.14
debugger disabled
  * WARNING: 'test: missing :bucket option should raise an argument error. ' is already defined
Loaded suite /var/lib/gems/1.8/gems/rake-0.9.2/lib/rake/rake_test_loader
Started
..................................................................................................................../home/mike/lib/paperclip/test/attachment_test.rb:564: warning: multiple values for a block parameter (0 for 1)
    from /usr/lib/ruby/1.8/test/unit/assertions.rb:123
....................................................................................sh: identify: not found
..identify: unable to open image `/home/This File Does Not Exist.omg': gick-6.6.0/modules-Q16/coders/omg.la @ error/blob.c/OpenBlob/2489.
....................identify: improper image header `/tmp/stream20111021-16545-1drlniu-0.png' @ error/png.c/ReadPNGImage/2957.
identify: improper image header `/tmp/stream20111021-16545-1drlniu-0.png' @ error/png.c/ReadPNGImage/2957.
identify: improper image header `/tmp/stream20111021-16545-1drlniu-0.png' @ error/png.c/ReadPNGImage/2957.
.identify: improper image header `/tmp/stream20111021-16545-ab5gtx-0.png' @ error/png.c/ReadPNGImage/2957.
identify: improper image header `/tmp/stream20111021-16545-ab5gtx-0.png' @ error/png.c/ReadPNGImage/2957.
identify: improper image header `/tmp/stream20111021-16545-ab5gtx-0.png' @ error/png.c/ReadPNGImage/2957.
..............[DEPRECATION] validates_attachment_thumbnail is deprecated. This validation is on by default and will be removed from future versions. If you wish to turn it off, supply :whiny => false in your definition.
........Permission denied - /home/mike/lib/paperclip/public/system/avatars/1/original/5k.png - skipping file
.Permission denied - /home/mike/lib/paperclip/public/system/avatars/1/original/5k.png - skipping file
.....................................................................................................................................................................................................sh: convert: not found
..............convert: unrecognized option `-this-aint-no-option' @ error/convert.c/ConvertImageCommand/2777.
.sh: convert: not found
....convert: unrecognized option `-this-aint-no-option' @ error/convert.c/ConvertImageCommand/2777.
...../home/mike/lib/paperclip/test/thumbnail_test.rb:256: warning: already initialized constant GeoParser
.........................................................
Finished in 47.907005 seconds.

524 tests, 918 assertions, 0 failures, 0 errors
/usr/bin/ruby1.8 -S bundle exec cucumber --format progress
..................................F--.........................................................

(::) failed steps (::)

expected there to be content "Name: something" in "Action Controller: Exception caught\n    body { background-color: #fff; color: #333; }\n\n    body, p, ol, ul, td {\n      font-family: verdana, arial, helvetica, sans-serif;\n      font-size:   13px;\n      line-height: 18px;\n    }\n\n    pre {\n      background-color: #eee;\n      padding: 10px;\n      font-size: 11px;\n    }\n\n    a { color: #000; }\n    a:visited { color: #666; }\n    a:hover { color: #fff; background-color:#000; }\n  \n\n\n  FakeWeb::NetConnectNotAllowedError\n  \n    in UsersController#create\n  \n\nReal HTTP connections are disabled. Unregistered request: PUT https://paperclip.s3.amazonaws.com/attachments/1/original/5k.png\n\n\n\nRAILS_ROOT: /home/mike/lib/paperclip/tmp/aruba/testapp\n\n\n  \n    \n    Application Trace |\n  \n    \n    Framework Trace |\n  \n    \n    Full Trace \n  \n\n  \n    \n      /var/lib/gems/1.8/gems/fakeweb-1.3.0/lib/fake_web/ext/net_http.rb:53:in `request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/http/net_http_handler.rb:29:in `handle'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/http/net_http_handler.rb:45:in `http_session_for'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/http/net_http_handler.rb:27:in `handle'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:207:in `make_sync_request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:219:in `retry_server_errors'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:202:in `make_sync_request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:342:in `client_request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client_logging.rb:25:in `log_client_request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client_logging.rb:24:in `log_client_request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:317:in `client_request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:255:in `return_or_raise'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:316:in `client_request'\n(eval):3:in `put_object'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/s3/s3_object.rb:305:in `write'\n/home/mike/lib/paperclip/lib/paperclip/storage/s3.rb:279:in `flush_writes'\n/home/mike/lib/paperclip/lib/paperclip/storage/s3.rb:270:in `each'\n/home/mike/lib/paperclip/lib/paperclip/storage/s3.rb:270:in `flush_writes'\n/home/mike/lib/paperclip/lib/paperclip/attachment.rb:176:in `save'\n/home/mike/lib/paperclip/lib/paperclip.rb:460:in `send'\n/home/mike/lib/paperclip/lib/paperclip.rb:460:in `save_attached_files'\n/home/mike/lib/paperclip/lib/paperclip.rb:453:in `each_attachment'\n/home/mike/lib/paperclip/lib/paperclip.rb:452:in `each'\n/home/mike/lib/paperclip/lib/paperclip.rb:452:in `each_attachment'\n/home/mike/lib/paperclip/lib/paperclip.rb:459:in `save_attached_files'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:178:in `send'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:178:in `evaluate_method'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:166:in `call'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:93:in `run'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:92:in `each'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:92:in `send'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:92:in `run'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:276:in `run_callbacks'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/callbacks.rb:344:in `callback'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/callbacks.rb:251:in `create_or_update'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/base.rb:2577:in `save_without_validation'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/validations.rb:1089:in `save_without_dirty'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/dirty.rb:79:in `save_without_transactions'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:229:in `send'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:229:in `with_transaction_returning_status'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:182:in `transaction'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:228:in `with_transaction_returning_status'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:196:in `save'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:208:in `rollback_active_record_state!'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:196:in `save'\n/home/mike/lib/paperclip/tmp/aruba/testapp/app/controllers/users_controller.rb:46:in `create'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/mime_responds.rb:106:in `call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/mime_responds.rb:106:in `respond_to'\n/home/mike/lib/paperclip/tmp/aruba/testapp/app/controllers/users_controller.rb:45:in `create'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:1333:in `send'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:1333:in `perform_action_without_filters'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/filters.rb:617:in `call_filters'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/filters.rb:610:in `perform_action_without_benchmark'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/core_ext/benchmark.rb:17:in `ms'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/core_ext/benchmark.rb:17:in `ms'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/rescue.rb:160:in `perform_action_without_flash'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/flash.rb:151:in `perform_action'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:532:in `send'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:532:in `process_without_filters'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/filters.rb:606:in `process'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:391:in `process'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:386:in `call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/routing/route_set.rb:438:in `call'\n    \n  \n    \n      /usr/lib/ruby/1.8/benchmark.rb:293:in `measure'\n/usr/lib/ruby/1.8/benchmark.rb:308:in `realtime'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:87:in `dispatch'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:121:in `_call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:130:in `build_middleware_stack'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:114:in `call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:108:in `call'\n    \n  \n    \n      /var/lib/gems/1.8/gems/fakeweb-1.3.0/lib/fake_web/ext/net_http.rb:53:in `request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/http/net_http_handler.rb:29:in `handle'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/http/net_http_handler.rb:45:in `http_session_for'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/http/net_http_handler.rb:27:in `handle'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:207:in `make_sync_request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:219:in `retry_server_errors'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:202:in `make_sync_request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:342:in `client_request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client_logging.rb:25:in `log_client_request'\n/usr/lib/ruby/1.8/benchmark.rb:293:in `measure'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client_logging.rb:24:in `log_client_request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:317:in `client_request'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:255:in `return_or_raise'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/core/client.rb:316:in `client_request'\n(eval):3:in `put_object'\n/var/lib/gems/1.8/gems/aws-sdk-1.2.1/lib/aws/s3/s3_object.rb:305:in `write'\n/home/mike/lib/paperclip/lib/paperclip/storage/s3.rb:279:in `flush_writes'\n/home/mike/lib/paperclip/lib/paperclip/storage/s3.rb:270:in `each'\n/home/mike/lib/paperclip/lib/paperclip/storage/s3.rb:270:in `flush_writes'\n/home/mike/lib/paperclip/lib/paperclip/attachment.rb:176:in `save'\n/home/mike/lib/paperclip/lib/paperclip.rb:460:in `send'\n/home/mike/lib/paperclip/lib/paperclip.rb:460:in `save_attached_files'\n/home/mike/lib/paperclip/lib/paperclip.rb:453:in `each_attachment'\n/home/mike/lib/paperclip/lib/paperclip.rb:452:in `each'\n/home/mike/lib/paperclip/lib/paperclip.rb:452:in `each_attachment'\n/home/mike/lib/paperclip/lib/paperclip.rb:459:in `save_attached_files'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:178:in `send'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:178:in `evaluate_method'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:166:in `call'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:93:in `run'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:92:in `each'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:92:in `send'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:92:in `run'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/callbacks.rb:276:in `run_callbacks'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/callbacks.rb:344:in `callback'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/callbacks.rb:251:in `create_or_update'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/base.rb:2577:in `save_without_validation'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/validations.rb:1089:in `save_without_dirty'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/dirty.rb:79:in `save_without_transactions'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:229:in `send'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:229:in `with_transaction_returning_status'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:182:in `transaction'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:228:in `with_transaction_returning_status'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:196:in `save'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:208:in `rollback_active_record_state!'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/transactions.rb:196:in `save'\n/home/mike/lib/paperclip/tmp/aruba/testapp/app/controllers/users_controller.rb:46:in `create'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/mime_responds.rb:106:in `call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/mime_responds.rb:106:in `respond_to'\n/home/mike/lib/paperclip/tmp/aruba/testapp/app/controllers/users_controller.rb:45:in `create'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:1333:in `send'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:1333:in `perform_action_without_filters'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/filters.rb:617:in `call_filters'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/filters.rb:610:in `perform_action_without_benchmark'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/core_ext/benchmark.rb:17:in `ms'\n/usr/lib/ruby/1.8/benchmark.rb:308:in `realtime'\n/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/core_ext/benchmark.rb:17:in `ms'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/rescue.rb:160:in `perform_action_without_flash'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/flash.rb:151:in `perform_action'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:532:in `send'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:532:in `process_without_filters'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/filters.rb:606:in `process'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:391:in `process'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:386:in `call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/routing/route_set.rb:438:in `call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:87:in `dispatch'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:121:in `_call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:130:in `build_middleware_stack'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/query_cache.rb:29:in `call'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/query_cache.rb:29:in `call'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/connection_adapters/abstract/query_cache.rb:34:in `cache'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/query_cache.rb:9:in `cache'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/query_cache.rb:28:in `call'\n/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/connection_adapters/abstract/connection_pool.rb:361:in `call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/string_coercion.rb:25:in `call'\n/var/lib/gems/1.8/gems/rack-1.1.2/lib/rack/head.rb:9:in `call'\n/var/lib/gems/1.8/gems/rack-1.1.2/lib/rack/methodoverride.rb:24:in `call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/params_parser.rb:15:in `call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/session/cookie_store.rb:99:in `call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/failsafe.rb:26:in `call'\n/var/lib/gems/1.8/gems/rack-1.1.2/lib/rack/lock.rb:11:in `call'\n/var/lib/gems/1.8/gems/rack-1.1.2/lib/rack/lock.rb:11:in `synchronize'\n/var/lib/gems/1.8/gems/rack-1.1.2/lib/rack/lock.rb:11:in `call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:114:in `call'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/reloader.rb:34:in `run'\n/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:108:in `call'\n/var/lib/gems/1.8/gems/rails-2.3.14/lib/rails/rack/static.rb:31:in `call'\n/var/lib/gems/1.8/gems/rack-1.1.2/lib/rack/urlmap.rb:47:in `call'\n/var/lib/gems/1.8/gems/rack-1.1.2/lib/rack/urlmap.rb:41:in `each'\n/var/lib/gems/1.8/gems/rack-1.1.2/lib/rack/urlmap.rb:41:in `call'\n/var/lib/gems/1.8/gems/rack-test-0.6.1/lib/rack/mock_session.rb:30:in `request'\n/var/lib/gems/1.8/gems/rack-test-0.6.1/lib/rack/test.rb:219:in `process_request'\n/var/lib/gems/1.8/gems/rack-test-0.6.1/lib/rack/test.rb:66:in `post'\n(__FORWARDABLE__):3:in `__send__'\n(__FORWARDABLE__):3:in `post'\n/var/lib/gems/1.8/gems/capybara-1.1.1/lib/capybara/rack_test/browser.rb:62:in `send'\n/var/lib/gems/1.8/gems/capybara-1.1.1/lib/capybara/rack_test/browser.rb:62:in `process'\n/var/lib/gems/1.8/gems/capybara-1.1.1/lib/capybara/rack_test/browser.rb:27:in `submit'\n/var/lib/gems/1.8/gems/capybara-1.1.1/lib/capybara/rack_test/form.rb:64:in `submit'\n/var/lib/gems/1.8/gems/capybara-1.1.1/lib/capybara/rack_test/node.rb:59:in `click'\n/var/lib/gems/1.8/gems/capybara-1.1.1/lib/capybara/node/element.rb:99:in `click'\n/var/lib/gems/1.8/gems/capybara-1.1.1/lib/capybara/node/base.rb:46:in `wait_until'\n/var/lib/gems/1.8/gems/capybara-1.1.1/lib/capybara/node/element.rb:99:in `click'\n/var/lib/gems/1.8/gems/capybara-1.1.1/lib/capybara/node/actions.rb:38:in `click_button'\n(eval):2:in `send'\n(eval):2:in `click_button'\n/var/lib/gems/1.8/gems/capybara-1.1.1/lib/capybara/dsl.rb:161:in `click_button'\n/home/mike/lib/paperclip/features/step_definitions/web_steps.rb:53\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/core_ext/instance_exec.rb:48:in `instance_exec'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/core_ext/instance_exec.rb:48:in `cucumber_instance_exec'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/core_ext/instance_exec.rb:69:in `cucumber_run_with_backtrace_filtering'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/core_ext/instance_exec.rb:36:in `cucumber_instance_exec'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/rb_support/rb_step_definition.rb:62:in `invoke'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/step_match.rb:25:in `invoke'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/step_invocation.rb:59:in `invoke'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/step_invocation.rb:38:in `accept'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:99:in `visit_step'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:163:in `broadcast'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:98:in `visit_step'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/step_collection.rb:15:in `accept'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/step_collection.rb:14:in `each'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/step_collection.rb:14:in `accept'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:93:in `visit_steps'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:163:in `broadcast'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:92:in `visit_steps'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/scenario.rb:55:in `accept'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/runtime.rb:79:in `with_hooks'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/runtime.rb:95:in `before_and_after'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/runtime.rb:78:in `with_hooks'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/runtime/support_code.rb:120:in `call'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/runtime/support_code.rb:120:in `around'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/language_support/language_methods.rb:13:in `around'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/language_support/language_methods.rb:95:in `call'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/language_support/language_methods.rb:95:in `execute_around'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/language_support/language_methods.rb:12:in `around'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/runtime/support_code.rb:119:in `around'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/runtime/support_code.rb:117:in `call'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/runtime/support_code.rb:117:in `around'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/runtime.rb:90:in `around'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/runtime.rb:77:in `with_hooks'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/scenario.rb:53:in `accept'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/scenario.rb:108:in `with_visitor'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/scenario.rb:47:in `accept'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:51:in `visit_feature_element'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:163:in `broadcast'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:50:in `visit_feature_element'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/feature.rb:43:in `accept'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/feature.rb:42:in `each'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/feature.rb:42:in `accept'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:20:in `visit_feature'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:163:in `broadcast'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:19:in `visit_feature'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/features.rb:29:in `accept'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/features.rb:17:in `each'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/features.rb:17:in `each'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/features.rb:28:in `accept'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:14:in `visit_features'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:163:in `broadcast'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/ast/tree_walker.rb:13:in `visit_features'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/runtime.rb:45:in `run!'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/cli/main.rb:43:in `execute!'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/lib/cucumber/cli/main.rb:20:in `execute'\n/var/lib/gems/1.8/gems/cucumber-1.0.6/bin/cucumber:14\n/var/lib/gems/1.8/bin/cucumber:19:in `load'\n/var/lib/gems/1.8/bin/cucumber:19\n    \n  \n\n\n\n\n\n\n\nRequest\nParameters: {\"commit\"=>\"Submit\",\n \"user\"=>{\"name\"=>\"something\",\n \"attachment\"=>#<File:/tmp/RackMultipart20111021-17655-edb1n3-0>}}\n\nShow session dump\n--- \n\n\n\nResponse\nHeaders: {\"Content-Type\"=>\"\",\n \"Cache-Control\"=>\"no-cache\"}\n\n\n\n" (RSpec::Expectations::ExpectationNotMetError)
./features/step_definitions/web_steps.rb:107:in `/^(?:|I )should see "([^"]*)"$/'
features/basic_integration.feature:45:in `Then I should see "Name: something"'

Failing Scenarios:
cucumber features/basic_integration.feature:26 # Scenario: S3 Integration test

6 scenarios (1 failed, 5 passed)
82 steps (1 failed, 2 skipped, 79 passed)
5m29.331s
rake aborted!
Command failed with status (1): [/usr/bin/ruby1.8 -S bundle exec cucumber -...]

Tasks: TOP => cucumber
(See full trace by running task with --trace)
Prem Sichanugrist
Admin

I've tried to merge this one in, and see a test failure. I think we should switch to aws-sdk, and it would be great if you can help us fix it. :)

Igor Alexandrov

I have created storage module for Paperclip that uses aws-sdk. Works well, using it in production projects myself.
https://github.com/igor-alexandrov/paperclip-aws

Prem Sichanugrist
Admin
Prem Sichanugrist sikachu referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Prem Sichanugrist sikachu referenced this pull request from a commit
Prem Sichanugrist sikachu Use AWS::SDK instead of AWS::S3
The original commit came from @amazonwebservices and @trevorrowe in #579.
I had to revise the commit and make sure all the test cases are passing.
All credits still goes to those guys, thanks a lot!
75f413d
Prem Sichanugrist sikachu closed this
Adam Tait adamtait referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 29, 2011
  1. Replace aws-s3 storage backend with the AWS SDK for Ruby.

    amazonwebservices authored
Commits on Oct 10, 2011
  1. Trevor Rowe

    Merge remote branch 'thoughtbot/master' into aws-sdk-backend

    trevorrowe authored
    Conflicts:
    	Gemfile
    	Gemfile.lock
    	features/support/s3.rb
    	gemfiles/rails2.gemfile
    	gemfiles/rails2.gemfile.lock
    	gemfiles/rails3.gemfile
    	gemfiles/rails3.gemfile.lock
    	gemfiles/rails3_1.gemfile
    	gemfiles/rails3_1.gemfile.lock
    	lib/paperclip/storage/s3.rb
    	test/storage/s3_test.rb
Commits on Oct 12, 2011
  1. Trevor Rowe
  2. Trevor Rowe
Commits on Oct 28, 2011
  1. Trevor Rowe
This page is out of date. Refresh to see the latest.
2  Gemfile
View
@@ -3,7 +3,7 @@ source "http://rubygems.org"
gem "activerecord", :require => "active_record"
gem "appraisal"
gem "aruba"
-gem "aws-s3", :require => "aws/s3"
+gem "aws-sdk", "~>1.0"
gem "bundler"
gem "cocaine", "~>0.2"
gem "fog"
1  features/basic_integration.feature
View
@@ -22,6 +22,7 @@ Feature: Rails integration
And I should see an image with a path of "/system/attachments/1/original/5k.png"
And the file at "/system/attachments/1/original/5k.png" should be the same as "test/fixtures/5k.png"
+ @s3
Scenario: S3 Integration test
Given I add this snippet to the User model:
"""
2  features/step_definitions/rails_steps.rb
View
@@ -10,7 +10,7 @@
gem "sqlite3"
gem "capybara"
gem "gherkin"
- gem "aws-s3"
+ gem "aws-sdk"
"""
And I configure the application to use "paperclip" from this project
And I reset Bundler environment variable
2  features/step_definitions/s3_steps.rb
View
@@ -1,6 +1,6 @@
When /^I attach the file "([^"]*)" to "([^"]*)" on S3$/ do |file_path, field|
definition = User.attachment_definitions[field.downcase.to_sym]
- path = "http://s3.amazonaws.com/paperclip#{definition[:path]}"
+ path = "https://paperclip.s3.amazonaws.com#{definition[:path]}"
path.gsub!(':filename', File.basename(file_path))
path.gsub!(/:([^\/\.]+)/) do |match|
"([^\/\.]+)"
25 gemfiles/rails2.gemfile
View
@@ -1,25 +0,0 @@
-# This file was generated by Appraisal
-
-source "http://rubygems.org"
-
-gem "activerecord", :require=>"active_record"
-gem "appraisal"
-gem "aruba"
-gem "aws-s3", :require=>"aws/s3"
-gem "bundler"
-gem "cocaine", "~>0.2"
-gem "fog"
-gem "jruby-openssl", :platform=>:jruby
-gem "mime-types"
-gem "mocha"
-gem "rake"
-gem "rdoc", :require=>false
-gem "capybara"
-gem "cucumber", "~> 1.0.0"
-gem "shoulda"
-gem "sqlite3", "~>1.3.4"
-gem "fakeweb", :require=>false
-gem "pry"
-gem "rails", "~> 2.3.14"
-gem "paperclip", :path=>"../"
-
25 gemfiles/rails3.gemfile
View
@@ -1,25 +0,0 @@
-# This file was generated by Appraisal
-
-source "http://rubygems.org"
-
-gem "activerecord", :require=>"active_record"
-gem "appraisal"
-gem "aruba"
-gem "aws-s3", :require=>"aws/s3"
-gem "bundler"
-gem "cocaine", "~>0.2"
-gem "fog"
-gem "jruby-openssl", :platform=>:jruby
-gem "mime-types"
-gem "mocha"
-gem "rake"
-gem "rdoc", :require=>false
-gem "capybara"
-gem "cucumber", "~> 1.0.0"
-gem "shoulda"
-gem "sqlite3", "~>1.3.4"
-gem "fakeweb", :require=>false
-gem "pry"
-gem "rails", "~> 3.0.10"
-gem "paperclip", :path=>"../"
-
25 gemfiles/rails3_1.gemfile
View
@@ -1,25 +0,0 @@
-# This file was generated by Appraisal
-
-source "http://rubygems.org"
-
-gem "activerecord", :require=>"active_record"
-gem "appraisal"
-gem "aruba"
-gem "aws-s3", :require=>"aws/s3"
-gem "bundler"
-gem "cocaine", "~>0.2"
-gem "fog"
-gem "jruby-openssl", :platform=>:jruby
-gem "mime-types"
-gem "mocha"
-gem "rake"
-gem "rdoc", :require=>false
-gem "capybara"
-gem "cucumber", "~> 1.0.0"
-gem "shoulda"
-gem "sqlite3", "~>1.3.4"
-gem "fakeweb", :require=>false
-gem "pry"
-gem "rails", "~> 3.1.0"
-gem "paperclip", :path=>"../"
-
2  lib/paperclip/options.rb
View
@@ -43,7 +43,9 @@ def initialize(attachment, hash)
@s3_permissions = hash[:s3_permissions]
@s3_protocol = hash[:s3_protocol]
@s3_headers = hash[:s3_headers]
+ @s3_metadata = hash[:s3_metadata]
@s3_host_alias = hash[:s3_host_alias]
+ @s3_storage_class = hash[:s3_storage_class]
#fog options
@fog_directory = hash[:fog_directory]
107 lib/paperclip/storage/s3.rb
View
@@ -1,5 +1,8 @@
+require 'uri'
+
module Paperclip
module Storage
+
# Amazon's S3 file hosting service is a scalable, easy place to store files for
# distribution. You can find out more about it at http://aws.amazon.com/s3
# There are a few S3-specific options for has_attached_file:
@@ -67,12 +70,21 @@ module Storage
# S3 (strictly speaking) does not support directories, you can still use a / to
# separate parts of your file name.
# * +s3_host_name+: If you are using your bucket in Tokyo region etc, write host_name.
+ # * +s3_metadata+: These key/value pairs will be stored with the
+ # object. This option works by prefixing each key with
+ # "x-amz-meta-" before sending it as a header on the object
+ # upload request.
+ # * +s3_storage_class+: If this option is set to
+ # <tt>:reduced_redundancy</tt>, the object will be stored using Reduced
+ # Redundancy Storage. RRS enables customers to reduce their
+ # costs by storing non-critical, reproducible data at lower
+ # levels of redundancy than Amazon S3's standard storage.
module S3
def self.extended base
begin
require 'aws/s3'
rescue LoadError => e
- e.message << " (You may need to install the aws-s3 gem)"
+ e.message << " (You may need to install the aws-sdk gem)"
raise e
end unless defined?(AWS::S3)
@@ -83,7 +95,21 @@ def self.extended base
Proc.new do |style|
(@s3_permissions[style.to_sym] || @s3_permissions[:default]) == :public_read ? 'http' : 'https'
end
- @s3_headers = @options.s3_headers || {}
+
+ @s3_metadata = @options.s3_metadata || {}
+ @s3_headers = (@options.s3_headers || {}).inject({}) do |headers,(name,value)|
+ case name.to_s
+ when /^x-amz-meta-(.*)/i
+ @s3_metadata[$1.downcase] = value
+ else
+ name = name.to_s.downcase.sub(/^x-amz-/,'').tr("-","_").to_sym
+ headers[name] = value
+ end
+ headers
+ end
+
+ @s3_headers[:storage_class] = @options.s3_storage_class if
+ @options.s3_storage_class
unless @options.url.to_s.match(/^:s3.*url$/) || @options.url == ":asset_host"
@options.path = @options.path.gsub(/:url/, @options.url).gsub(/^:rails_root\/public\/system/, '')
@@ -92,14 +118,7 @@ def self.extended base
@options.url = @options.url.inspect if @options.url.is_a?(Symbol)
@http_proxy = @options.http_proxy || nil
- if @http_proxy
- @s3_options.merge!({:proxy => @http_proxy})
- end
- AWS::S3::Base.establish_connection!( @s3_options.merge(
- :access_key_id => s3_credentials[:access_key_id],
- :secret_access_key => s3_credentials[:secret_access_key]
- ))
end
Paperclip.interpolates(:s3_alias_url) do |attachment, style|
"#{attachment.s3_protocol(style)}://#{attachment.s3_host_alias}/#{attachment.path(style).gsub(%r{^/}, "")}"
@@ -116,7 +135,10 @@ def self.extended base
end
def expiring_url(time = 3600, style_name = default_style)
- AWS::S3::S3Object.url_for(path(style_name), bucket_name, :expires_in => time, :use_ssl => (s3_protocol(style_name) == 'https'))
+ s3_object(style_name).url_for(:read,
+ :expires => time,
+ :secure =>
+ (s3_protocol(style_name) == 'https')).to_s
end
def s3_credentials
@@ -136,7 +158,43 @@ def s3_host_alias
def bucket_name
@bucket = @options.bucket || s3_credentials[:bucket]
@bucket = @bucket.call(self) if @bucket.is_a?(Proc)
- @bucket
+ @bucket or raise ArgumentError, "missing required :bucket option"
+ end
+
+ def s3_interface
+ @s3_interface ||= begin
+
+ config = {}
+
+ config[:s3_endpoint] = s3_host_name
+
+ if using_http_proxy?
+ proxy_opts = {}
+ proxy_opts[:host] = http_proxy_host
+ proxy_opts[:port] = http_proxy_port if http_proxy_port
+ if http_proxy_user
+ userinfo = http_proxy_user.to_s
+ userinfo += ":#{http_proxy_password}" if http_proxy_password
+ proxy_opts[:userinfo] = userinfo
+ end
+ config[:proxy_uri] = URI::HTTP.build(proxy_opts)
+ end
+
+ [:access_key_id, :secret_access_key].each do |opt|
+ config[opt] = s3_credentials[opt] if s3_credentials[opt]
+ end
+
+ AWS::S3.new(config.merge(@s3_options))
+
+ end
+ end
+
+ def s3_bucket
+ @s3_bucket ||= s3_interface.buckets[bucket_name]
+ end
+
+ def s3_object style_name = default_style
+ s3_bucket.objects[path(style_name).sub(%r{^/},'')]
end
def using_http_proxy?
@@ -176,7 +234,7 @@ def parse_credentials creds
def exists?(style = default_style)
if original_filename
- AWS::S3::S3Object.exists?(path(style), bucket_name)
+ s3_object(style).exists?
else
false
end
@@ -199,30 +257,29 @@ def to_file style = default_style
basename = File.basename(filename, extname)
file = Tempfile.new([basename, extname])
file.binmode
- file.write(AWS::S3::S3Object.value(path(style), bucket_name))
+ file.write(s3_object(style).read)
file.rewind
return file
end
def create_bucket
- AWS::S3::Bucket.create(bucket_name)
+ s3_interface.buckets.create(bucket_name)
end
def flush_writes #:nodoc:
@queued_for_write.each do |style, file|
begin
log("saving #{path(style)}")
- AWS::S3::S3Object.store(path(style),
- file,
- bucket_name,
- {:content_type => file.content_type.to_s.strip,
- :access => (@s3_permissions[style] || @s3_permissions[:default]),
- }.merge(@s3_headers))
- rescue AWS::S3::NoSuchBucket => e
+ write_options = {
+ :content_type => file.content_type.to_s.strip,
+ :acl => (@s3_permissions[style] || @s3_permissions[:default]),
+ }
+ write_options[:metadata] = @s3_metadata unless @s3_metadata.empty?
+ write_options.merge!(@s3_headers)
+ s3_object(style).write(file, write_options)
+ rescue AWS::S3::Errors::NoSuchBucket => e
create_bucket
retry
- rescue AWS::S3::ResponseError => e
- raise
end
end
@@ -235,8 +292,8 @@ def flush_deletes #:nodoc:
@queued_for_delete.each do |path|
begin
log("deleting #{path}")
- AWS::S3::S3Object.delete(path, bucket_name)
- rescue AWS::S3::ResponseError
+ s3_bucket.objects[path.sub(%r{^/},'')].delete
+ rescue AWS::Errors::Base => e
# Ignore this.
end
end
398 test/storage/s3_test.rb
View
@@ -1,5 +1,9 @@
+require 'aws'
+
+AWS.stub!
+AWS.config(:access_key_id => "TESTKEY", :secret_access_key => "TESTSECRET")
+
require './test/helper'
-require 'aws/s3'
class S3Test < Test::Unit::TestCase
def rails_env(env)
@@ -11,7 +15,6 @@ def rails_env(env)
context "Parsing S3 credentials" do
setup do
@proxy_settings = {:host => "127.0.0.1", :port => 8888, :user => "foo", :password => "bar"}
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
:bucket => "testing",
:http_proxy => @proxy_settings,
@@ -51,9 +54,73 @@ def rails_env(env)
end
+ context "missing :bucket option" do
+
+ setup do
+ rebuild_model :storage => :s3,
+ #:bucket => "testing", # intentionally left out
+ :s3_credentials => {:not => :important}
+
+ @dummy = Dummy.new
+ @dummy.avatar = StringIO.new(".")
+
+ end
+
+ should "raise an argument error" do
+ exception = assert_raise(ArgumentError) { @dummy.save }
+ assert_match /missing required :bucket option/, exception.message
+ end
+
+ end
+
+ context ":bucket option via :s3_credentials" do
+
+ setup do
+ rebuild_model :storage => :s3, :s3_credentials => {:bucket => 'testing'}
+ @dummy = Dummy.new
+ end
+
+ should "populate #bucket_name" do
+ assert_equal @dummy.avatar.bucket_name, 'testing'
+ end
+
+ end
+
+ context ":bucket option" do
+
+ setup do
+ rebuild_model :storage => :s3, :bucket => "testing", :s3_credentials => {}
+ @dummy = Dummy.new
+ end
+
+ should "populate #bucket_name" do
+ assert_equal @dummy.avatar.bucket_name, 'testing'
+ end
+
+ end
+
+ context "missing :bucket option" do
+
+ setup do
+ rebuild_model :storage => :s3,
+ #:bucket => "testing", # intentionally left out
+ :http_proxy => @proxy_settings,
+ :s3_credentials => {:not => :important}
+
+ @dummy = Dummy.new
+ @dummy.avatar = StringIO.new(".")
+
+ end
+
+ should "raise an argument error" do
+ exception = assert_raise(ArgumentError) { @dummy.save }
+ assert_match /missing required :bucket option/, exception.message
+ end
+
+ end
+
context "" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
:s3_credentials => {},
:bucket => "bucket",
@@ -66,11 +133,46 @@ def rails_env(env)
should "return a url based on an S3 path" do
assert_match %r{^http://s3.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
end
+
+ should "use the correct bucket" do
+ assert_equal "bucket", @dummy.avatar.s3_bucket.name
+ end
+
+ should "use the correct key" do
+ assert_equal "avatars/stringio.txt", @dummy.avatar.s3_object.key
+ end
+
+ end
+
+ context "An attachment that uses S3 for storage and has the style in the path" do
+ setup do
+ rebuild_model :storage => :s3,
+ :bucket => "testing",
+ :path => ":attachment/:style/:basename.:extension",
+ :styles => {
+ :thumb => "80x80>"
+ },
+ :s3_credentials => {
+ 'access_key_id' => "12345",
+ 'secret_access_key' => "54321"
+ }
+
+ @dummy = Dummy.new
+ @dummy.avatar = StringIO.new(".")
+ @avatar = @dummy.avatar
+ end
+
+ should "use an S3 object based on the correct path for the default style" do
+ assert_equal("avatars/original/stringio.txt", @dummy.avatar.s3_object.key)
+ end
+
+ should "use an S3 object based on the correct path for the custom style" do
+ assert_equal("avatars/thumb/stringio.txt", @dummy.avatar.s3_object(:thumb).key)
+ end
end
context "s3_host_name" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
:s3_credentials => {},
:bucket => "bucket",
@@ -83,11 +185,14 @@ def rails_env(env)
should "return a url based on an :s3_host_name path" do
assert_match %r{^http://s3-ap-northeast-1.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
end
+
+ should "use the S3 bucket with the correct host name" do
+ assert_equal "s3-ap-northeast-1.amazonaws.com", @dummy.avatar.s3_bucket.config.s3_endpoint
+ end
end
context "An attachment that uses S3 for storage and has styles that return different file types" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :styles => { :large => ['500x500#', :jpg] },
:storage => :s3,
:bucket => "bucket",
@@ -105,14 +210,21 @@ def rails_env(env)
assert_match /.+\/5k.png/, @dummy.avatar.url
end
+ should 'use the correct key for the original file mime type' do
+ assert_match /.+\/5k.png/, @dummy.avatar.s3_object.key
+ end
+
should "return a url containing the correct processed file mime type" do
assert_match /.+\/5k.jpg/, @dummy.avatar.url(:large)
end
+
+ should "use the correct key for the processed file mime type" do
+ assert_match /.+\/5k.jpg/, @dummy.avatar.s3_object(:large).key
+ end
end
context "An attachment that uses S3 for storage and has spaces in file name" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :styles => { :large => ['500x500#', :jpg] },
:storage => :s3,
:bucket => "bucket",
@@ -136,7 +248,6 @@ def rails_env(env)
context "" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
:s3_credentials => {},
:bucket => "bucket",
@@ -153,7 +264,6 @@ def rails_env(env)
context "" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
:s3_credentials => {
:production => { :bucket => "prod_bucket" },
@@ -173,7 +283,6 @@ def rails_env(env)
context "generating a url with a proc as the host alias" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
:s3_credentials => { :bucket => "prod_bucket" },
:s3_host_alias => Proc.new{|atch| "cdn#{atch.instance.counter % 4}.example.com"},
@@ -203,7 +312,6 @@ def counter
context "" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
:s3_credentials => {},
:bucket => "bucket",
@@ -220,7 +328,6 @@ def counter
context "Generating a secure url with an expiration" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
:s3_credentials => {
:production => { :bucket => "prod_bucket" },
@@ -236,7 +343,9 @@ def counter
@dummy = Dummy.new
@dummy.avatar = StringIO.new(".")
- AWS::S3::S3Object.expects(:url_for).with("avatars/stringio.txt", "prod_bucket", { :expires_in => 3600, :use_ssl => true })
+ object = stub
+ @dummy.avatar.stubs(:s3_object).returns(object)
+ object.expects(:url_for).with(:read, :expires => 3600, :secure => true)
@dummy.avatar.expiring_url
end
@@ -246,9 +355,8 @@ def counter
end
end
- context "Generating a url with an expiration" do
+ context "Generating a url with an expiration for each style" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
:s3_credentials => {
:production => { :bucket => "prod_bucket" },
@@ -263,22 +371,25 @@ def counter
@dummy = Dummy.new
@dummy.avatar = StringIO.new(".")
+ end
- AWS::S3::S3Object.expects(:url_for).with("avatars/original/stringio.txt", "prod_bucket", { :expires_in => 3600, :use_ssl => true })
- @dummy.avatar.expiring_url
-
- AWS::S3::S3Object.expects(:url_for).with("avatars/thumb/stringio.txt", "prod_bucket", { :expires_in => 1800, :use_ssl => true })
+ should "should generate a url for the thumb" do
+ object = stub
+ @dummy.avatar.stubs(:s3_object).with(:thumb).returns(object)
+ object.expects(:url_for).with(:read, :expires => 1800, :secure => true)
@dummy.avatar.expiring_url(1800, :thumb)
end
- should "should succeed" do
- assert true
+ should "should generate a url for the default style" do
+ object = stub
+ @dummy.avatar.stubs(:s3_object).with(:original).returns(object)
+ object.expects(:url_for).with(:read, :expires => 1800, :secure => true)
+ @dummy.avatar.expiring_url(1800)
end
end
context "Parsing S3 credentials with a bucket in them" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
:s3_credentials => {
:production => { :bucket => "prod_bucket" },
@@ -290,18 +401,20 @@ def counter
should "get the right bucket in production" do
rails_env("production")
assert_equal "prod_bucket", @dummy.avatar.bucket_name
+ assert_equal "prod_bucket", @dummy.avatar.s3_bucket.name
end
should "get the right bucket in development" do
rails_env("development")
assert_equal "dev_bucket", @dummy.avatar.bucket_name
+ assert_equal "dev_bucket", @dummy.avatar.s3_bucket.name
end
end
context "Parsing S3 credentials with a s3_host_name in them" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
+ :bucket => 'testing',
:s3_credentials => {
:production => { :s3_host_name => "s3-world-end.amazonaws.com" },
:development => { :s3_host_name => "s3-ap-northeast-1.amazonaws.com" }
@@ -312,16 +425,19 @@ def counter
should "get the right s3_host_name in production" do
rails_env("production")
assert_match %r{^s3-world-end.amazonaws.com}, @dummy.avatar.s3_host_name
+ assert_match %r{^s3-world-end.amazonaws.com}, @dummy.avatar.s3_bucket.config.s3_endpoint
end
should "get the right s3_host_name in development" do
rails_env("development")
assert_match %r{^s3-ap-northeast-1.amazonaws.com}, @dummy.avatar.s3_host_name
+ assert_match %r{^s3-ap-northeast-1.amazonaws.com}, @dummy.avatar.s3_bucket.config.s3_endpoint
end
should "get the right s3_host_name if the key does not exist" do
rails_env("test")
assert_match %r{^s3.amazonaws.com}, @dummy.avatar.s3_host_name
+ assert_match %r{^s3.amazonaws.com}, @dummy.avatar.s3_bucket.config.s3_endpoint
end
end
@@ -361,7 +477,11 @@ def counter
context "and saved" do
setup do
- AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path, anything, 'testing', :content_type => 'image/png', :access => :public_read)
+ object = stub
+ @dummy.avatar.stubs(:s3_object).returns(object)
+ object.expects(:write).with(anything,
+ :content_type => "image/png",
+ :acl => :public_read)
@dummy.save
end
@@ -371,21 +491,23 @@ def counter
end
should "delete tempfiles" do
- AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path, anything, 'testing', :content_type => 'image/png', :access => :public_read)
+
File.stubs(:exist?).returns(true)
Paperclip::Tempfile.any_instance.expects(:close).at_least_once()
Paperclip::Tempfile.any_instance.expects(:unlink).at_least_once()
@dummy.save!
+
end
context "and saved without a bucket" do
setup do
- class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
- # Force the class to be created as a proper subclass of ResponseError thanks to AWS::S3's autocreation of exceptions
- end
- AWS::S3::Bucket.expects(:create).with("testing")
- AWS::S3::S3Object.stubs(:store).raises(AWS::S3::NoSuchBucket.new(:message, :response)).then.returns(true)
+ AWS::S3::BucketCollection.any_instance.expects(:create).with("testing")
+ AWS::S3::S3Object.any_instance.stubs(:write).
+ raises(AWS::S3::Errors::NoSuchBucket.new(stub,
+ stub(:status => 404,
+ :body => "<foo/>"))).
+ then.returns(nil)
@dummy.save
end
@@ -396,8 +518,8 @@ class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
context "and remove" do
setup do
- AWS::S3::S3Object.stubs(:exists?).returns(true)
- AWS::S3::S3Object.stubs(:delete)
+ AWS::S3::S3Object.any_instance.stubs(:exists?).returns(true)
+ AWS::S3::S3Object.any_instance.stubs(:delete)
@dummy.destroy_attached_files
end
@@ -410,7 +532,6 @@ class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
context "An attachment with S3 storage and bucket defined as a Proc" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
:bucket => lambda { |attachment| "bucket_#{attachment.instance.other}" },
:s3_credentials => {:not => :important}
@@ -418,13 +539,14 @@ class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
should "get the right bucket name" do
assert "bucket_a", Dummy.new(:other => 'a').avatar.bucket_name
+ assert "bucket_a", Dummy.new(:other => 'a').avatar.s3_bucket.name
assert "bucket_b", Dummy.new(:other => 'b').avatar.bucket_name
+ assert "bucket_b", Dummy.new(:other => 'b').avatar.s3_bucket.name
end
end
context "An attachment with S3 storage and specific s3 headers set" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
rebuild_model :storage => :s3,
:bucket => "testing",
:path => ":attachment/:style/:basename.:extension",
@@ -446,13 +568,168 @@ class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
context "and saved" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
- AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path,
- anything,
- 'testing',
- :content_type => 'image/png',
- :access => :public_read,
- 'Cache-Control' => 'max-age=31557600')
+ object = stub
+ @dummy.avatar.stubs(:s3_object).returns(object)
+ object.expects(:write).with(anything,
+ :content_type => "image/png",
+ :acl => :public_read,
+ :cache_control => 'max-age=31557600')
+ @dummy.save
+ end
+
+ should "succeed" do
+ assert true
+ end
+ end
+ end
+ end
+
+ context "An attachment with S3 storage and metadata set using header names" do
+ setup do
+ rebuild_model :storage => :s3,
+ :bucket => "testing",
+ :path => ":attachment/:style/:basename.:extension",
+ :s3_credentials => {
+ 'access_key_id' => "12345",
+ 'secret_access_key' => "54321"
+ },
+ :s3_headers => {'x-amz-meta-color' => 'red'}
+ end
+
+ context "when assigned" do
+ setup do
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
+ @dummy = Dummy.new
+ @dummy.avatar = @file
+ end
+
+ teardown { @file.close }
+
+ context "and saved" do
+ setup do
+ object = stub
+ @dummy.avatar.stubs(:s3_object).returns(object)
+ object.expects(:write).with(anything,
+ :content_type => "image/png",
+ :acl => :public_read,
+ :metadata => { "color" => "red" })
+ @dummy.save
+ end
+
+ should "succeed" do
+ assert true
+ end
+ end
+ end
+ end
+
+ context "An attachment with S3 storage and metadata set using the :s3_metadata option" do
+ setup do
+ rebuild_model :storage => :s3,
+ :bucket => "testing",
+ :path => ":attachment/:style/:basename.:extension",
+ :s3_credentials => {
+ 'access_key_id' => "12345",
+ 'secret_access_key' => "54321"
+ },
+ :s3_metadata => { "color" => "red" }
+ end
+
+ context "when assigned" do
+ setup do
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
+ @dummy = Dummy.new
+ @dummy.avatar = @file
+ end
+
+ teardown { @file.close }
+
+ context "and saved" do
+ setup do
+ object = stub
+ @dummy.avatar.stubs(:s3_object).returns(object)
+ object.expects(:write).with(anything,
+ :content_type => "image/png",
+ :acl => :public_read,
+ :metadata => { "color" => "red" })
+ @dummy.save
+ end
+
+ should "succeed" do
+ assert true
+ end
+ end
+ end
+ end
+
+ context "An attachment with S3 storage and storage class set using the header name" do
+ setup do
+ rebuild_model :storage => :s3,
+ :bucket => "testing",
+ :path => ":attachment/:style/:basename.:extension",
+ :s3_credentials => {
+ 'access_key_id' => "12345",
+ 'secret_access_key' => "54321"
+ },
+ :s3_headers => { "x-amz-storage-class" => "reduced_redundancy" }
+ end
+
+ context "when assigned" do
+ setup do
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
+ @dummy = Dummy.new
+ @dummy.avatar = @file
+ end
+
+ teardown { @file.close }
+
+ context "and saved" do
+ setup do
+ object = stub
+ @dummy.avatar.stubs(:s3_object).returns(object)
+ object.expects(:write).with(anything,
+ :content_type => "image/png",
+ :acl => :public_read,
+ :storage_class => "reduced_redundancy")
+ @dummy.save
+ end
+
+ should "succeed" do
+ assert true
+ end
+ end
+ end
+ end
+
+ context "An attachment with S3 storage and storage class set using the :storage_class option" do
+ setup do
+ rebuild_model :storage => :s3,
+ :bucket => "testing",
+ :path => ":attachment/:style/:basename.:extension",
+ :s3_credentials => {
+ 'access_key_id' => "12345",
+ 'secret_access_key' => "54321"
+ },
+ :s3_storage_class => :reduced_redundancy
+ end
+
+ context "when assigned" do
+ setup do
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
+ @dummy = Dummy.new
+ @dummy.avatar = @file
+ end
+
+ teardown { @file.close }
+
+ context "and saved" do
+ setup do
+ object = stub
+ @dummy.avatar.stubs(:s3_object).returns(object)
+ object.expects(:write).with(anything,
+ :content_type => "image/png",
+ :acl => :public_read,
+ :storage_class => :reduced_redundancy)
@dummy.save
end
@@ -480,8 +757,8 @@ class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
should "parse the credentials" do
assert_equal 'pathname_bucket', @dummy.avatar.bucket_name
- assert_equal 'pathname_key', AWS::S3::Base.connection.options[:access_key_id]
- assert_equal 'pathname_secret', AWS::S3::Base.connection.options[:secret_access_key]
+ assert_equal 'pathname_key', @dummy.avatar.s3_bucket.config.access_key_id
+ assert_equal 'pathname_secret', @dummy.avatar.s3_bucket.config.secret_access_key
end
end
@@ -503,8 +780,8 @@ class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
should "run the file through ERB" do
assert_equal 'env_bucket', @dummy.avatar.bucket_name
- assert_equal 'env_key', AWS::S3::Base.connection.options[:access_key_id]
- assert_equal 'env_secret', AWS::S3::Base.connection.options[:secret_access_key]
+ assert_equal 'env_key', @dummy.avatar.s3_bucket.config.access_key_id
+ assert_equal 'env_secret', @dummy.avatar.s3_bucket.config.secret_access_key
end
end
@@ -531,12 +808,11 @@ class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
context "and saved" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
- AWS::S3::S3Object.expects(:store).with(@dummy.avatar.path,
- anything,
- 'testing',
- :content_type => 'image/png',
- :access => :public_read)
+ object = stub
+ @dummy.avatar.stubs(:s3_object).returns(object)
+ object.expects(:write).with(anything,
+ :content_type => "image/png",
+ :acl => :public_read)
@dummy.save
end
@@ -570,12 +846,11 @@ class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
context "and saved" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
- AWS::S3::S3Object.expects(:store).with(@dummy.avatar.path,
- anything,
- 'testing',
- :content_type => 'image/png',
- :access => 'private')
+ object = stub
+ @dummy.avatar.stubs(:s3_object).returns(object)
+ object.expects(:write).with(anything,
+ :content_type => "image/png",
+ :acl => 'private')
@dummy.save
end
@@ -615,13 +890,12 @@ class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
context "and saved" do
setup do
- AWS::S3::Base.stubs(:establish_connection!)
[:thumb, :original].each do |style|
- AWS::S3::S3Object.expects(:store).with("avatars/#{style}/5k.png",
- anything,
- 'testing',
- :content_type => 'image/png',
- :access => style == :thumb ? 'public-read' : 'private')
+ object = stub
+ @dummy.avatar.stubs(:s3_object).with(style).returns(object)
+ object.expects(:write).with(anything,
+ :content_type => "image/png",
+ :acl => style == :thumb ? 'public-read' : 'private')
end
@dummy.save
end
Something went wrong with that request. Please try again.