paperclip 3.5.2 → 3.5.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of paperclip might be problematic. Click here for more details.

Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +9 -0
  3. data/Appraisals +3 -3
  4. data/Gemfile +3 -8
  5. data/NEWS +22 -0
  6. data/README.md +61 -12
  7. data/gemfiles/3.0.gemfile +2 -2
  8. data/gemfiles/3.1.gemfile +2 -2
  9. data/gemfiles/3.2.gemfile +2 -2
  10. data/gemfiles/4.0.gemfile +2 -2
  11. data/lib/paperclip.rb +3 -2
  12. data/lib/paperclip/attachment.rb +13 -2
  13. data/lib/paperclip/attachment_registry.rb +3 -1
  14. data/lib/paperclip/content_type_detector.rb +2 -4
  15. data/lib/paperclip/geometry_detector_factory.rb +8 -3
  16. data/lib/paperclip/has_attached_file.rb +1 -1
  17. data/lib/paperclip/interpolations.rb +4 -4
  18. data/lib/paperclip/io_adapters/abstract_adapter.rb +1 -1
  19. data/lib/paperclip/io_adapters/data_uri_adapter.rb +1 -1
  20. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +1 -1
  21. data/lib/paperclip/storage/fog.rb +16 -8
  22. data/lib/paperclip/storage/s3.rb +26 -14
  23. data/lib/paperclip/tempfile_factory.rb +1 -3
  24. data/lib/paperclip/validators.rb +3 -1
  25. data/lib/paperclip/version.rb +1 -1
  26. data/paperclip.gemspec +0 -4
  27. data/shoulda_macros/paperclip.rb +14 -3
  28. data/test/attachment_registry_test.rb +11 -0
  29. data/test/attachment_test.rb +30 -1
  30. data/test/content_type_detector_test.rb +1 -0
  31. data/test/file_command_content_type_detector_test.rb +2 -0
  32. data/test/generator_test.rb +6 -2
  33. data/test/has_attached_file_test.rb +3 -3
  34. data/test/helper.rb +18 -1
  35. data/test/integration_test.rb +4 -5
  36. data/test/io_adapters/abstract_adapter_test.rb +1 -1
  37. data/test/io_adapters/attachment_adapter_test.rb +6 -3
  38. data/test/io_adapters/data_uri_adapter_test.rb +7 -0
  39. data/test/io_adapters/empty_string_adapter_test.rb +1 -0
  40. data/test/io_adapters/file_adapter_test.rb +48 -32
  41. data/test/storage/fog_test.rb +28 -8
  42. data/test/storage/s3_test.rb +8 -0
  43. data/test/tempfile_factory_test.rb +4 -0
  44. data/test/validators/attachment_content_type_validator_test.rb +1 -0
  45. data/test/validators_test.rb +29 -0
  46. metadata +42 -95
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ea82fb0a61da2668522387c0791072a70b799a34
4
+ data.tar.gz: a66594b8fe23229892f4472f38adead04f6eb803
5
+ SHA512:
6
+ metadata.gz: 61d7b295e78e6403728a1589caf7a835482bf68d47c41720fa1cb594f2e5db0af43abf1015d4407c7f203701301ef611526bbe60f597187f49c7dce10ac5dc41
7
+ data.tar.gz: d45aeb9b2662ba922d2d2e5a15b350cb23b1a1bc0a682bfd03a5272d74122c8ad19458d12acf041811f84a20a356d06bb1c18c9694a95edf890fbe4fac5a13dc
@@ -4,6 +4,10 @@ rvm:
4
4
  - jruby-19mode
5
5
  - rbx-19mode
6
6
  - 2.0.0
7
+ - 2.1.0
8
+
9
+ install:
10
+ - "bundle install"
7
11
 
8
12
  before_script: "sudo ntpdate -ub ntp.ubuntu.com pool.ntp.org; true"
9
13
  script: "bundle exec rake clean test cucumber"
@@ -12,8 +16,13 @@ gemfile:
12
16
  - gemfiles/3.0.gemfile
13
17
  - gemfiles/3.1.gemfile
14
18
  - gemfiles/3.2.gemfile
19
+ - gemfiles/4.0.gemfile
15
20
 
16
21
  matrix:
17
22
  allow_failures:
18
23
  - rvm: jruby-19mode
19
24
  - rvm: rbx-19mode
25
+
26
+ exclude:
27
+ - rvm: 1.9.2
28
+ gemfile: gemfiles/4.0.gemfile
data/Appraisals CHANGED
@@ -1,15 +1,15 @@
1
1
  appraise "3.0" do
2
- gem "rails", "~> 3.0.15"
2
+ gem "rails", "~> 3.0.20"
3
3
  gem "paperclip", :path => "../"
4
4
  end
5
5
 
6
6
  appraise "3.1" do
7
- gem "rails", "~> 3.1.6"
7
+ gem "rails", "~> 3.1.12"
8
8
  gem "paperclip", :path => "../"
9
9
  end
10
10
 
11
11
  appraise "3.2" do
12
- gem "rails", "~> 3.2.6"
12
+ gem "rails", "~> 3.2.15"
13
13
  gem "paperclip", :path => "../"
14
14
  end
15
15
 
data/Gemfile CHANGED
@@ -2,12 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- platform :jruby do
6
- gem 'jruby-openssl'
7
- gem 'activerecord-jdbcsqlite3-adapter'
8
- end
5
+ gem 'jruby-openssl', :platform => :jruby
6
+ gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby
9
7
 
10
- platform :ruby do
11
- gem 'pry'
12
- gem 'pry-debugger'
13
- end
8
+ gem 'pry', :platform => :ruby
data/NEWS CHANGED
@@ -1,3 +1,25 @@
1
+ New in 3.5.3:
2
+
3
+ Improvement: After three long, hard years... we know how to upgrade
4
+ Bug Fix: #expiring_url returns 'missing' urls if nothing is attached
5
+ Improvement: Lots of documentation fixes
6
+ Improvement: Lots of fixes for Ruby warnings
7
+ Improvement: Test the most appropriate Ruby/Rails comobinations on Travis
8
+ Improvement: Delegate more IO methods through IOAdapters
9
+ Improvement: Remove Rails 4 deprecations
10
+ Improvement: Both S3's and Fog's #expiring_url can take a Time or Int
11
+ Bug Fix: Both S3's and Fog's expiring_url respect style when missing the file
12
+ Bug Fix: Timefiles will have a reasonable-length name. They're all MD5 hashes now
13
+ Bug Fix: Don't delete files off S3 when reprocessing due to AWS inconsistencies
14
+ Bug Fix: "swallow_stream" isn't thread dafe. Use :swallow_stderr
15
+ Improvement: Regexps use \A and \Z instead of ^ and $
16
+ Improvement: :s3_credentials can take a lambda as an argument
17
+ Improvement: Search up the class heirarchy for attachments
18
+ Improvement: deep_merge options instead of regular merge
19
+ Bug Fix: Prevent file deletion on transaction rollback
20
+ Test Improvement: Ensure more files are properly closed during tests
21
+ Test Bug Fix: Return the gemfile's syntax to normal
22
+
1
23
  New in 3.5.2:
2
24
 
3
25
  * Security: Force cocaine to at least 0.5.3 to include a security fix
data/README.md CHANGED
@@ -88,15 +88,17 @@ For Non-Rails usage:
88
88
 
89
89
  ```ruby
90
90
  class ModuleName < ActiveRecord::Base
91
- include Paperclip::Glue
92
- ...
91
+ include Paperclip::Glue
92
+ ...
93
93
  end
94
94
  ```
95
95
 
96
96
  Quick Start
97
97
  -----------
98
98
 
99
- In your model:
99
+ ### Models
100
+
101
+ **Rails 3**
100
102
 
101
103
  ```ruby
102
104
  class User < ActiveRecord::Base
@@ -105,7 +107,15 @@ class User < ActiveRecord::Base
105
107
  end
106
108
  ```
107
109
 
108
- In your migrations:
110
+ **Rails 4**
111
+
112
+ ```ruby
113
+ class User < ActiveRecord::Base
114
+ has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
115
+ end
116
+ ```
117
+
118
+ ### Migrations
109
119
 
110
120
  ```ruby
111
121
  class AddAvatarColumnsToUsers < ActiveRecord::Migration
@@ -121,7 +131,7 @@ end
121
131
 
122
132
  (Or you can use migration generator: `rails generate paperclip user avatar`)
123
133
 
124
- In your edit and new views:
134
+ ### Edit and New Views
125
135
 
126
136
  ```erb
127
137
  <%= form_for @user, :url => users_path, :html => { :multipart => true } do |form| %>
@@ -129,7 +139,9 @@ In your edit and new views:
129
139
  <% end %>
130
140
  ```
131
141
 
132
- In your controller:
142
+ ### Controller
143
+
144
+ **Rails 3**
133
145
 
134
146
  ```ruby
135
147
  def create
@@ -137,7 +149,24 @@ def create
137
149
  end
138
150
  ```
139
151
 
140
- In your show view:
152
+ **Rails 4**
153
+
154
+ ```ruby
155
+ def create
156
+ @user = User.create( user_params )
157
+ end
158
+
159
+ private
160
+
161
+ # Use strong_parameters for attribute whitelisting
162
+ # Be sure to update your create() and update() controller methods.
163
+
164
+ def user_params
165
+ params.require(:user).permit(:avatar)
166
+ end
167
+ ```
168
+
169
+ ### Show View
141
170
 
142
171
  ```erb
143
172
  <%= image_tag @user.avatar.url %>
@@ -145,7 +174,9 @@ In your show view:
145
174
  <%= image_tag @user.avatar.url(:thumb) %>
146
175
  ```
147
176
 
148
- To detach a file, simply set the attribute to `nil`:
177
+ ### Deleting an Attachment
178
+
179
+ Set the attribute to `nil` and save.
149
180
 
150
181
  ```ruby
151
182
  @user.avatar = nil
@@ -253,6 +284,24 @@ class BooksController < ApplicationController
253
284
  end
254
285
  ```
255
286
 
287
+ **A note on content_type validations and security**
288
+
289
+ You should ensure that you validate files to be only those MIME types you
290
+ explicitly want to support. If you don't, you could be open to
291
+ <a href="https://www.owasp.org/index.php/Testing_for_Stored_Cross_site_scripting_(OWASP-DV-002)">XSS attacks</a>
292
+ if a user uploads a file with a malicious HTML payload.
293
+
294
+ If you're only interested in images, restrict your allowed content_types to
295
+ image-y ones:
296
+
297
+ ```ruby
298
+ validates_attachment :avatar,
299
+ :content_type => { :content_type => ["image/jpg", "image/gif", "image/png"] }
300
+ ```
301
+
302
+ `Paperclip::ContentTypeDetector` will attempt to match a file's extension to an
303
+ inferred content_type, regardless of the actual contents of the file.
304
+
256
305
  Defaults
257
306
  --------
258
307
  Global defaults for all your paperclip attachments can be defined by changing the Paperclip::Attachment.default_options Hash, this can be useful for setting your default storage settings per example so you won't have to define them in every has_attached_file definition.
@@ -556,7 +605,7 @@ look as follows where a boss will receive a `300x300` thumbnail otherwise a
556
605
 
557
606
  ```ruby
558
607
  class User < ActiveRecord::Base
559
- has_attached_file :avatar, :styles => lambda { |attachment| { :thumb => (attachment.instance.boss? ? "300x300>" : "100x100>") }
608
+ has_attached_file :avatar, :styles => lambda { |attachment| { :thumb => (attachment.instance.boss? ? "300x300>" : "100x100>") } }
560
609
  end
561
610
  ```
562
611
 
@@ -683,11 +732,11 @@ If you'd like to contribute a feature or bugfix: Thanks! To make sure your
683
732
  fix/feature has a high chance of being included, please read the following
684
733
  guidelines:
685
734
 
686
- 1. Ask on the [mailing list](http://groups.google.com/group/paperclip-plugin), or
687
- post a new [GitHub Issue](http://github.com/thoughtbot/paperclip/issues).
735
+ 1. Post a [pull request](https://github.com/thoughtbot/paperclip/compare/).
688
736
  2. Make sure there are tests! We will not accept any patch that is not tested.
689
737
  It's a rare time when explicit tests aren't needed. If you have questions
690
- about writing tests for paperclip, please ask the mailing list.
738
+ about writing tests for paperclip, please open a
739
+ [GitHub issue](https://github.com/thoughtbot/paperclip/issues/new).
691
740
 
692
741
  Please see `CONTRIBUTING.md` for more details on contributing and running test.
693
742
 
@@ -4,8 +4,8 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "jruby-openssl", :platform=>:jruby
6
6
  gem "activerecord-jdbcsqlite3-adapter", :platform=>:jruby
7
- gem "sqlite3", :platform=>:ruby
8
- gem "rails", "~> 3.0.15"
7
+ gem "pry", :platform=>:ruby
8
+ gem "rails", "~> 3.0.20"
9
9
  gem "paperclip", :path=>"../"
10
10
 
11
11
  gemspec :path=>"../"
@@ -4,8 +4,8 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "jruby-openssl", :platform=>:jruby
6
6
  gem "activerecord-jdbcsqlite3-adapter", :platform=>:jruby
7
- gem "sqlite3", :platform=>:ruby
8
- gem "rails", "~> 3.1.6"
7
+ gem "pry", :platform=>:ruby
8
+ gem "rails", "~> 3.1.12"
9
9
  gem "paperclip", :path=>"../"
10
10
 
11
11
  gemspec :path=>"../"
@@ -4,8 +4,8 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "jruby-openssl", :platform=>:jruby
6
6
  gem "activerecord-jdbcsqlite3-adapter", :platform=>:jruby
7
- gem "sqlite3", :platform=>:ruby
8
- gem "rails", "~> 3.2.6"
7
+ gem "pry", :platform=>:ruby
8
+ gem "rails", "~> 3.2.15"
9
9
  gem "paperclip", :path=>"../"
10
10
 
11
11
  gemspec :path=>"../"
@@ -4,8 +4,8 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "jruby-openssl", :platform=>:jruby
6
6
  gem "activerecord-jdbcsqlite3-adapter", :platform=>:jruby
7
- gem "sqlite3", :platform=>:ruby
7
+ gem "pry", :platform=>:ruby
8
8
  gem "rails", "~> 4.0.0"
9
9
  gem "paperclip", :path=>"../"
10
10
 
11
- gemspec :path=>"../"
11
+ gemspec :path=>"../"
@@ -129,8 +129,9 @@ module Paperclip
129
129
  # :default_style => :normal
130
130
  # user.avatar.url # => "/avatars/23/normal_me.png"
131
131
  # * +keep_old_files+: Keep the existing attachment files (original + resized) from
132
- # being automatically deleted when an attachment is cleared or updated.
133
- # Defaults to +false+.#
132
+ # being automatically deleted when an attachment is cleared or updated. Defaults to +false+.
133
+ # * +preserve_files+: Keep the existing attachment files in all cases, even if the parent
134
+ # record is destroyed. Defaults to +false+.
134
135
  # * +whiny+: Will raise an error if Paperclip cannot post_process an uploaded file due
135
136
  # to a command line error. This will override the global setting for this attachment.
136
137
  # Defaults to true.
@@ -69,7 +69,7 @@ module Paperclip
69
69
  @name = name
70
70
  @instance = instance
71
71
 
72
- options = self.class.default_options.merge(options)
72
+ options = self.class.default_options.deep_merge(options)
73
73
 
74
74
  @options = options
75
75
  @post_processing = true
@@ -312,8 +312,12 @@ module Paperclip
312
312
  # in the paperclip:refresh rake task and that's it. It will regenerate all
313
313
  # thumbnails forcefully, by reobtaining the original file and going through
314
314
  # the post-process again.
315
+ # NOTE: Calling reprocess WILL NOT delete existing files. This is due to
316
+ # inconsistencies in timing of S3 commands. It's possible that calling
317
+ # #reprocess! will lose data if the files are not kept.
315
318
  def reprocess!(*style_args)
316
319
  saved_only_process, @options[:only_process] = @options[:only_process], style_args
320
+ saved_preserve_files, @options[:preserve_files] = @options[:preserve_files], true
317
321
  begin
318
322
  assign(self)
319
323
  save
@@ -323,6 +327,7 @@ module Paperclip
323
327
  false
324
328
  ensure
325
329
  @options[:only_process] = saved_only_process
330
+ @options[:preserve_files] = saved_preserve_files
326
331
  end
327
332
  end
328
333
 
@@ -429,10 +434,16 @@ module Paperclip
429
434
  def post_process_style(name, style) #:nodoc:
430
435
  begin
431
436
  raise RuntimeError.new("Style #{name} has no processors defined.") if style.processors.blank?
437
+ original_file = @queued_for_write[:original]
432
438
  @queued_for_write[name] = style.processors.inject(@queued_for_write[:original]) do |file, processor|
433
- Paperclip.processor(processor).make(file, style.processor_options, self)
439
+ new_file = Paperclip.processor(processor).make(file, style.processor_options, self)
440
+ file.close unless file == original_file
441
+ new_file
434
442
  end
443
+ unadapted_file = @queued_for_write[name]
435
444
  @queued_for_write[name] = Paperclip.io_adapters.for(@queued_for_write[name])
445
+ unadapted_file.close if unadapted_file.respond_to?(:close)
446
+ @queued_for_write[name]
436
447
  rescue Paperclip::Error => e
437
448
  log("An error was received while processing: #{e.inspect}")
438
449
  (@errors[:processing] ||= []) << e.message if @options[:whiny]
@@ -51,7 +51,9 @@ module Paperclip
51
51
  end
52
52
 
53
53
  def definitions_for(klass)
54
- @attachments[klass]
54
+ klass.ancestors.each_with_object({}) do |ancestor, inherited_definitions|
55
+ inherited_definitions.merge! @attachments[ancestor]
56
+ end
55
57
  end
56
58
  end
57
59
  end
@@ -46,15 +46,13 @@ module Paperclip
46
46
  def empty_file?
47
47
  File.exists?(@filename) && File.size(@filename) == 0
48
48
  end
49
+
50
+ alias :empty? :empty_file?
49
51
 
50
52
  def blank_name?
51
53
  @filename.nil? || @filename.empty?
52
54
  end
53
55
 
54
- def empty?
55
- File.exists?(@filename) && File.size(@filename) == 0
56
- end
57
-
58
56
  def possible_types
59
57
  MIME::Types.type_for(@filename).collect(&:content_type)
60
58
  end
@@ -14,9 +14,14 @@ module Paperclip
14
14
 
15
15
  def geometry_string
16
16
  begin
17
- silence_stream(STDERR) do
18
- Paperclip.run("identify", "-format '%wx%h,%[exif:orientation]' :file", :file => "#{path}[0]")
19
- end
17
+ Paperclip.run(
18
+ "identify",
19
+ "-format '%wx%h,%[exif:orientation]' :file", {
20
+ :file => "#{path}[0]"
21
+ }, {
22
+ :swallow_stderr => true
23
+ }
24
+ )
20
25
  rescue Cocaine::ExitStatusError
21
26
  ""
22
27
  rescue Cocaine::CommandNotFoundError => e
@@ -81,7 +81,7 @@ module Paperclip
81
81
  name = @name
82
82
  @klass.send(:after_save) { send(name).send(:save) }
83
83
  @klass.send(:before_destroy) { send(name).send(:queue_all_for_delete) }
84
- @klass.send(:after_destroy) { send(name).send(:flush_deletes) }
84
+ @klass.send(:after_commit, :on => :destroy) { send(name).send(:flush_deletes) }
85
85
  end
86
86
 
87
87
  def add_paperclip_callbacks
@@ -48,7 +48,7 @@ module Paperclip
48
48
  # Returns the interpolated URL. Will raise an error if the url itself
49
49
  # contains ":url" to prevent infinite recursion. This interpolation
50
50
  # is used in the default :path to ease default specifications.
51
- RIGHT_HERE = "#{__FILE__.gsub(%r{^\./}, "")}:#{__LINE__ + 3}"
51
+ RIGHT_HERE = "#{__FILE__.gsub(%r{\A\./}, "")}:#{__LINE__ + 3}"
52
52
  def url attachment, style_name
53
53
  raise Errors::InfiniteInterpolationError if caller.any?{|b| b.index(RIGHT_HERE) }
54
54
  attachment.url(style_name, :timestamp => false, :escape => false)
@@ -90,7 +90,7 @@ module Paperclip
90
90
 
91
91
  # Returns the basename of the file. e.g. "file" for "file.jpg"
92
92
  def basename attachment, style_name
93
- attachment.original_filename.gsub(/#{Regexp.escape(File.extname(attachment.original_filename))}$/, "")
93
+ attachment.original_filename.gsub(/#{Regexp.escape(File.extname(attachment.original_filename))}\Z/, "")
94
94
  end
95
95
 
96
96
  # Returns the extension of the file. e.g. "jpg" for "file.jpg"
@@ -98,7 +98,7 @@ module Paperclip
98
98
  # of the actual extension.
99
99
  def extension attachment, style_name
100
100
  ((style = attachment.styles[style_name.to_s.to_sym]) && style[:format]) ||
101
- File.extname(attachment.original_filename).gsub(/^\.+/, "")
101
+ File.extname(attachment.original_filename).gsub(/\A\.+/, "")
102
102
  end
103
103
 
104
104
  # Returns an extension based on the content type. e.g. "jpeg" for
@@ -128,7 +128,7 @@ module Paperclip
128
128
  # It's possible, though unlikely, that the mime type is not in the
129
129
  # database, so just use the part after the '/' in the mime type as the
130
130
  # extension.
131
- %r{/([^/]*)$}.match(attachment.content_type)[1]
131
+ %r{/([^/]*)\Z}.match(attachment.content_type)[1]
132
132
  end
133
133
  end
134
134
 
@@ -5,7 +5,7 @@ module Paperclip
5
5
  OS_RESTRICTED_CHARACTERS = %r{[/:]}
6
6
 
7
7
  attr_reader :content_type, :original_filename, :size
8
- delegate :close, :closed?, :eof?, :path, :rewind, :unlink, :to => :@tempfile
8
+ delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :rewind, :unlink, :to => :@tempfile
9
9
 
10
10
  def fingerprint
11
11
  @fingerprint ||= Digest::MD5.file(path).to_s