paperclip 2.4.1 → 2.4.2

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.

data/README.md CHANGED
@@ -60,6 +60,12 @@ Or, if you don't use Bundler (though you probably should, even in Rails 2), with
60
60
  config.gem "paperclip", :version => "~> 2.4"
61
61
  ...
62
62
  end
63
+ For Non-Rails usage:
64
+
65
+ class ModuleName < ActiveRecord::Base
66
+ include Paperclip::Glue
67
+ ...
68
+ end
63
69
 
64
70
  Quick Start
65
71
  -----------
@@ -203,7 +209,7 @@ styles, no processors will be run if there are no styles defined._
203
209
  If you're interested in caching your thumbnail's width, height and size in the
204
210
  database, take a look at the [paperclip-meta](https://github.com/y8/paperclip-meta) gem.
205
211
 
206
- Also, if you're interesting to generate the thumbnail on-the-fly, you might want
212
+ Also, if you're interested in generating the thumbnail on-the-fly, you might want
207
213
  to look into the [attachment_on_the_fly](https://github.com/drpentode/Attachment-on-the-Fly) gem.
208
214
 
209
215
  Events
@@ -227,7 +233,9 @@ called with valid attachments._
227
233
  URI Obfuscation
228
234
  ---------------
229
235
 
230
- Paperclip has an interpolation called `:hash` for obfuscating filenames of publicly-available files. For more on this feature read author's own explanation.
236
+ Paperclip has an interpolation called `:hash` for obfuscating filenames of
237
+ publicly-available files. For more on this feature read the author's own
238
+ explanation.
231
239
 
232
240
  [https://github.com/thoughtbot/paperclip/pull/416](https://github.com/thoughtbot/paperclip/pull/416)
233
241
 
@@ -269,7 +277,7 @@ a few utility examples would be compression and encryption processors.
269
277
  Dynamic Configuration
270
278
  ---------------------
271
279
 
272
- Callable objects (labdas, Procs) can be used in a number of places for dynamic
280
+ Callable objects (lambdas, Procs) can be used in a number of places for dynamic
273
281
  configuration throughout Paperclip. This strategy exists in a number of
274
282
  components of the library but is most significant in the possibilities for
275
283
  allowing custom styles and processors to be applied for specific model
@@ -322,7 +330,7 @@ Here is an example for Capistrano:
322
330
  run "cd #{release_path}; RAILS_ENV=production bundle exec rake paperclip:refresh:missing_styles"
323
331
  end
324
332
  end
325
-
333
+
326
334
  after("deploy:update_code", "deploy:build_missing_paperclip_styles")
327
335
 
328
336
  Now you don't have to remember to refresh thumbnails in production everytime you add new style.
@@ -334,7 +342,7 @@ Paperclip about existing styles. Simply create paperclip_attachments.yml file by
334
342
  class User < ActiveRecord::Base
335
343
  has_attached_file :avatar, :styles => {:thumb => 'x100', :croppable => '600x600>', :big => '1000x1000>'}
336
344
  end
337
-
345
+
338
346
  class Book < ActiveRecord::Base
339
347
  has_attached_file :cover, :styles => {:small => 'x100', :large => '1000x1000>'}
340
348
  has_attached_file :sample, :styles => {:thumb => 'x100'}
@@ -342,17 +350,17 @@ Paperclip about existing styles. Simply create paperclip_attachments.yml file by
342
350
 
343
351
  Then in `RAILS_ROOT/public/system/paperclip_attachments.yml`:
344
352
 
345
- ---
346
- :User:
347
- :avatar:
353
+ ---
354
+ :User:
355
+ :avatar:
348
356
  - :thumb
349
357
  - :croppable
350
358
  - :big
351
- :Book:
352
- :cover:
359
+ :Book:
360
+ :cover:
353
361
  - :small
354
362
  - :large
355
- :sample:
363
+ :sample:
356
364
  - :thumb
357
365
 
358
366
  Testing
@@ -97,7 +97,8 @@ module Paperclip
97
97
  if options[:image_magick_path]
98
98
  Paperclip.log("[DEPRECATION] :image_magick_path is deprecated and will be removed. Use :command_path instead")
99
99
  end
100
- Cocaine::CommandLine.path = options[:command_path] || options[:image_magick_path]
100
+ command_path = options[:command_path] || options[:image_magick_path]
101
+ Cocaine::CommandLine.path = ( Cocaine::CommandLine.path ? [Cocaine::CommandLine.path, command_path ].flatten : command_path )
101
102
  Cocaine::CommandLine.new(cmd, *params).run
102
103
  end
103
104
 
@@ -184,6 +185,19 @@ module Paperclip
184
185
  raise e
185
186
  end
186
187
  end
188
+
189
+ def check_for_url_clash(name,url,klass)
190
+ @names_url ||= {}
191
+ default_url = url || Attachment.default_options[:url]
192
+ if @names_url[name] && @names_url[name][:url] == default_url && @names_url[name][:class] != klass
193
+ log("Duplicate URL for #{name} with #{default_url}. This will clash with attachment defined in #{@names_url[name][:class]} class")
194
+ end
195
+ @names_url[name] = {:url => default_url, :class => klass}
196
+ end
197
+
198
+ def reset_duplicate_clash_check!
199
+ @names_url = nil
200
+ end
187
201
  end
188
202
 
189
203
  class PaperclipError < StandardError #:nodoc:
@@ -277,6 +291,20 @@ module Paperclip
277
291
  # choices are :filesystem and :s3. The default is :filesystem. Make sure you read the
278
292
  # documentation for Paperclip::Storage::Filesystem and Paperclip::Storage::S3
279
293
  # for backend-specific options.
294
+ #
295
+ # It's also possible for you to dynamicly define your interpolation string for :url,
296
+ # :default_url, and :path in your model by passing a method name as a symbol as a argument
297
+ # for your has_attached_file definition:
298
+ #
299
+ # class Person
300
+ # has_attached_file :avatar, :default_url => :default_url_by_gender
301
+ #
302
+ # private
303
+ #
304
+ # def default_url_by_gender
305
+ # "/assets/avatars/default_#{gender}.png"
306
+ # end
307
+ # end
280
308
  def has_attached_file name, options = {}
281
309
  include InstanceMethods
282
310
 
@@ -289,7 +317,8 @@ module Paperclip
289
317
  end
290
318
 
291
319
  attachment_definitions[name] = {:validations => []}.merge(options)
292
- Paperclip.classes_with_attachments << self
320
+ Paperclip.classes_with_attachments << self unless Paperclip.classes_with_attachments.include?(self)
321
+ Paperclip.check_for_url_clash(name,attachment_definitions[name][:url],self.name)
293
322
 
294
323
  after_save :save_attached_files
295
324
  before_destroy :prepare_for_destroy
@@ -1,4 +1,6 @@
1
1
  # encoding: utf-8
2
+ require 'uri'
3
+
2
4
  module Paperclip
3
5
  # The Attachment class manages the files for a given attachment. It saves
4
6
  # when the model saves, deletes when the model is destroyed, and processes
@@ -115,6 +117,7 @@ module Paperclip
115
117
  ensure_required_accessors!
116
118
 
117
119
  if uploaded_file.is_a?(Paperclip::Attachment)
120
+ uploaded_filename = uploaded_file.original_filename
118
121
  uploaded_file = uploaded_file.to_file(:original)
119
122
  close_uploaded_file = uploaded_file.respond_to?(:close)
120
123
  end
@@ -126,8 +129,9 @@ module Paperclip
126
129
 
127
130
  return nil if uploaded_file.nil?
128
131
 
132
+ uploaded_filename ||= uploaded_file.original_filename
129
133
  @queued_for_write[:original] = to_tempfile(uploaded_file)
130
- instance_write(:file_name, uploaded_file.original_filename.strip)
134
+ instance_write(:file_name, uploaded_filename.strip)
131
135
  instance_write(:content_type, uploaded_file.content_type.to_s.strip)
132
136
  instance_write(:file_size, uploaded_file.size.to_i)
133
137
  instance_write(:fingerprint, generate_fingerprint(uploaded_file))
@@ -153,7 +157,7 @@ module Paperclip
153
157
  def url(style_name = default_style, use_timestamp = @use_timestamp)
154
158
  default_url = @default_url.is_a?(Proc) ? @default_url.call(self) : @default_url
155
159
  url = original_filename.nil? ? interpolate(default_url, style_name) : interpolate(@url, style_name)
156
- use_timestamp && updated_at ? [url, updated_at].compact.join(url.include?("?") ? "&" : "?") : url
160
+ URI.escape(use_timestamp && updated_at ? [url, updated_at].compact.join(url.include?("?") ? "&" : "?") : url)
157
161
  end
158
162
 
159
163
  # Returns the path of the attachment as defined by the :path option. If the
@@ -291,6 +295,7 @@ module Paperclip
291
295
  post_process(*style_args)
292
296
 
293
297
  old_original.close if old_original.respond_to?(:close)
298
+ old_original.unlink if old_original.respond_to?(:unlink)
294
299
 
295
300
  save
296
301
  else
@@ -25,7 +25,10 @@ module Paperclip
25
25
 
26
26
  # Perform the actual interpolation. Takes the pattern to interpolate
27
27
  # and the arguments to pass, which are the attachment and style name.
28
+ # You can pass a method name on your record as a symbol, which should turn
29
+ # an interpolation pattern for Paperclip to use.
28
30
  def self.interpolate pattern, *args
31
+ pattern = args.first.instance.send(pattern) if pattern.kind_of? Symbol
29
32
  all.reverse.inject( pattern.dup ) do |result, tag|
30
33
  result.gsub(/:#{tag}/) do |match|
31
34
  send( tag, *args )
@@ -136,8 +139,12 @@ module Paperclip
136
139
 
137
140
  # Returns a the attachment hash. See Paperclip::Attachment#hash for
138
141
  # more details.
139
- def hash attachment, style_name
140
- attachment.hash(style_name)
142
+ def hash attachment=nil, style_name=nil
143
+ if attachment && style_name
144
+ attachment.hash(style_name)
145
+ else
146
+ super()
147
+ end
141
148
  end
142
149
 
143
150
  # Returns the id of the instance in a split path form. e.g. returns
@@ -95,6 +95,12 @@ module Paperclip
95
95
  @url = ":s3_path_url"
96
96
  end
97
97
  @url = ":asset_host" if @options[:url].to_s == ":asset_host"
98
+
99
+ @http_proxy = @options[:http_proxy] || nil
100
+ if @http_proxy
101
+ @s3_options.merge!({:proxy => @http_proxy})
102
+ end
103
+
98
104
  AWS::S3::Base.establish_connection!( @s3_options.merge(
99
105
  :access_key_id => @s3_credentials[:access_key_id],
100
106
  :secret_access_key => @s3_credentials[:secret_access_key]
@@ -122,6 +128,26 @@ module Paperclip
122
128
  @bucket
123
129
  end
124
130
 
131
+ def using_http_proxy?
132
+ !!@http_proxy
133
+ end
134
+
135
+ def http_proxy_host
136
+ using_http_proxy? ? @http_proxy[:host] : nil
137
+ end
138
+
139
+ def http_proxy_port
140
+ using_http_proxy? ? @http_proxy[:port] : nil
141
+ end
142
+
143
+ def http_proxy_user
144
+ using_http_proxy? ? @http_proxy[:user] : nil
145
+ end
146
+
147
+ def http_proxy_password
148
+ using_http_proxy? ? @http_proxy[:password] : nil
149
+ end
150
+
125
151
  def s3_host_name
126
152
  @s3_host_name || "s3.amazonaws.com"
127
153
  end
@@ -1,3 +1,3 @@
1
1
  module Paperclip
2
- VERSION = "2.4.1" unless defined? Paperclip::VERSION
2
+ VERSION = "2.4.2" unless defined? Paperclip::VERSION
3
3
  end
@@ -36,6 +36,13 @@ class AttachmentTest < Test::Unit::TestCase
36
36
  assert_equal "fake_models/blegga.png", @attachment.url
37
37
  end
38
38
 
39
+ should "return the url by executing and interpolating the default_url when assigned with symbol as method in attachment model" do
40
+ @attachment = attachment :default_url => :some_method_to_determine_default_url
41
+ @model = @attachment.instance
42
+ @model.stubs(:some_method_to_determine_default_url).returns(":class/female_:style_blegga.png")
43
+ assert_equal "fake_models/female_foostyle_blegga.png", @attachment.url(:foostyle)
44
+ end
45
+
39
46
  context "Attachment default_options" do
40
47
  setup do
41
48
  rebuild_model
@@ -911,7 +918,22 @@ class AttachmentTest < Test::Unit::TestCase
911
918
  end
912
919
  end
913
920
  end
921
+ end
922
+
923
+ context "with a file that has space in file name" do
924
+ setup do
925
+ @attachment.stubs(:instance_read).with(:file_name).returns("spaced file.png")
926
+ @attachment.stubs(:instance_read).with(:content_type).returns("image/png")
927
+ @attachment.stubs(:instance_read).with(:file_size).returns(12345)
928
+ dtnow = DateTime.now
929
+ @now = Time.now
930
+ Time.stubs(:now).returns(@now)
931
+ @attachment.stubs(:instance_read).with(:updated_at).returns(dtnow)
932
+ end
914
933
 
934
+ should "returns an escaped version of the URL" do
935
+ assert_match /\/spaced%20file\.png/, @attachment.url
936
+ end
915
937
  end
916
938
 
917
939
  context "when trying a nonexistant storage type" do
@@ -53,7 +53,6 @@ class FogTest < Test::Unit::TestCase
53
53
  @dummy.avatar = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
54
54
  end
55
55
  should "be able to interpolate the path without blowing up" do
56
- puts @dummy.avatar.instance_variable_get("@path")
57
56
  assert_equal File.expand_path(File.join(File.dirname(__FILE__), "../public/avatars/5k.png")),
58
57
  @dummy.avatar.path
59
58
  end
@@ -84,6 +84,7 @@ def rebuild_class options = {}
84
84
  ActiveRecord::Base.send(:include, Paperclip::Glue)
85
85
  Object.send(:remove_const, "Dummy") rescue nil
86
86
  Object.const_set("Dummy", Class.new(ActiveRecord::Base))
87
+ Paperclip.reset_duplicate_clash_check!
87
88
  Dummy.class_eval do
88
89
  include Paperclip::Glue
89
90
  has_attached_file :avatar, options
@@ -71,6 +71,22 @@ class IntegrationTest < Test::Unit::TestCase
71
71
  should "change the timestamp" do
72
72
  assert_not_equal @original_timestamp, @d2.avatar_updated_at
73
73
  end
74
+
75
+ should "clean up the old original if it is a tempfile" do
76
+ original = @d2.avatar.to_file(:original)
77
+ tf = Paperclip::Tempfile.new('original')
78
+ tf.binmode
79
+ original.binmode
80
+ tf.write(original.read)
81
+ original.close
82
+ tf.rewind
83
+
84
+ File.expects(:unlink).with(tf.instance_variable_get(:@tmpname))
85
+
86
+ @d2.avatar.expects(:to_file).with(:original).returns(tf)
87
+
88
+ @d2.avatar.reprocess!
89
+ end
74
90
  end
75
91
  end
76
92
 
@@ -171,13 +171,20 @@ class InterpolationsTest < Test::Unit::TestCase
171
171
  assert_equal seconds_since_epoch, Paperclip::Interpolations.updated_at(attachment, :style)
172
172
  end
173
173
 
174
- should "return hash" do
174
+ should "return attachment's hash when passing both arguments" do
175
175
  attachment = mock
176
176
  fake_hash = "a_wicked_secure_hash"
177
177
  attachment.expects(:hash).returns(fake_hash)
178
178
  assert_equal fake_hash, Paperclip::Interpolations.hash(attachment, :style)
179
179
  end
180
180
 
181
+ should "return Object#hash when passing no argument" do
182
+ attachment = mock
183
+ fake_hash = "a_wicked_secure_hash"
184
+ attachment.expects(:hash).never.returns(fake_hash)
185
+ assert_not_equal fake_hash, Paperclip::Interpolations.hash
186
+ end
187
+
181
188
  should "call all expected interpolations with the given arguments" do
182
189
  Paperclip::Interpolations.expects(:id).with(:attachment, :style).returns(1234)
183
190
  Paperclip::Interpolations.expects(:attachment).with(:attachment, :style).returns("attachments")
@@ -2,9 +2,23 @@ require './test/helper'
2
2
 
3
3
  class PaperclipTest < Test::Unit::TestCase
4
4
  context "Calling Paperclip.run" do
5
- should "run the command with Cocaine" do
5
+ setup do
6
6
  Cocaine::CommandLine.expects(:new).with("convert", "stuff").returns(stub(:run))
7
+ @original_command_line_path = Cocaine::CommandLine.path
8
+ end
9
+
10
+ teardown do
11
+ Cocaine::CommandLine.path = @original_command_line_path
12
+ end
13
+
14
+ should "run the command with Cocaine" do
15
+ Paperclip.run("convert", "stuff")
16
+ end
17
+
18
+ should "save Cocaine::CommandLine.path that set before" do
19
+ Cocaine::CommandLine.path = "/opt/my_app/bin"
7
20
  Paperclip.run("convert", "stuff")
21
+ assert_equal [Cocaine::CommandLine.path].flatten.include?("/opt/my_app/bin"), true
8
22
  end
9
23
  end
10
24
 
@@ -46,6 +60,24 @@ class PaperclipTest < Test::Unit::TestCase
46
60
  end
47
61
  end
48
62
 
63
+ context "Attachments with clashing URLs should raise error" do
64
+ setup do
65
+ class Dummy2 < ActiveRecord::Base
66
+ include Paperclip::Glue
67
+ end
68
+ end
69
+
70
+ should "generate warning if attachment is redefined with the same url string" do
71
+ Paperclip.expects(:log).with("Duplicate URL for blah with /system/:attachment/:id/:style/:filename. This will clash with attachment defined in Dummy class")
72
+ Dummy.class_eval do
73
+ has_attached_file :blah
74
+ end
75
+ Dummy2.class_eval do
76
+ has_attached_file :blah
77
+ end
78
+ end
79
+ end
80
+
49
81
  context "An ActiveRecord model with an 'avatar' attachment" do
50
82
  setup do
51
83
  rebuild_model :path => "tmp/:class/omg/:style.:extension"
@@ -0,0 +1,52 @@
1
+ require './test/helper'
2
+
3
+ class FileSystemTest < Test::Unit::TestCase
4
+ context "Filesystem" do
5
+ setup do
6
+ rebuild_model :styles => { :thumbnail => "25x25#" }
7
+ @dummy = Dummy.create!
8
+
9
+ @dummy.avatar = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "5k.png"))
10
+ end
11
+
12
+ should "allow file assignment" do
13
+ assert @dummy.save
14
+ end
15
+
16
+ should "store the original" do
17
+ @dummy.save
18
+ assert File.exists?(@dummy.avatar.path)
19
+ end
20
+
21
+ should "store the thumbnail" do
22
+ @dummy.save
23
+ assert File.exists?(@dummy.avatar.path(:thumbnail))
24
+ end
25
+
26
+ should "clean up file objects" do
27
+ File.stubs(:exist?).returns(true)
28
+ Paperclip::Tempfile.any_instance.expects(:close).at_least_once()
29
+ Paperclip::Tempfile.any_instance.expects(:unlink).at_least_once()
30
+
31
+ @dummy.save!
32
+ end
33
+
34
+ context "with file that has space in file name" do
35
+ setup do
36
+ rebuild_model :styles => { :thumbnail => "25x25#" }
37
+ @dummy = Dummy.create!
38
+
39
+ @dummy.avatar = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "spaced file.png"))
40
+ @dummy.save
41
+ end
42
+
43
+ should "store the file" do
44
+ assert File.exists?(@dummy.avatar.path)
45
+ end
46
+
47
+ should "return an escaped version of URL" do
48
+ assert_match /\/spaced%20file\.png/, @dummy.avatar.url
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,51 @@
1
+ require './test/helper'
2
+ require 'aws/s3'
3
+
4
+ unless ENV["S3_TEST_BUCKET"].blank?
5
+ class S3LiveTest < Test::Unit::TestCase
6
+ context "Using S3 for real, an attachment with S3 storage" do
7
+ setup do
8
+ rebuild_model :styles => { :thumb => "100x100", :square => "32x32#" },
9
+ :storage => :s3,
10
+ :bucket => ENV["S3_TEST_BUCKET"],
11
+ :path => ":class/:attachment/:id/:style.:extension",
12
+ :s3_credentials => File.new(File.join(File.dirname(__FILE__), "..", "s3.yml"))
13
+
14
+ Dummy.delete_all
15
+ @dummy = Dummy.new
16
+ end
17
+
18
+ should "be extended by the S3 module" do
19
+ assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
20
+ end
21
+
22
+ context "when assigned" do
23
+ setup do
24
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
25
+ @dummy.avatar = @file
26
+ end
27
+
28
+ teardown { @file.close }
29
+
30
+ should "still return a Tempfile when sent #to_file" do
31
+ assert_equal Paperclip::Tempfile, @dummy.avatar.to_file.class
32
+ end
33
+
34
+ context "and saved" do
35
+ setup do
36
+ @dummy.save
37
+ end
38
+
39
+ should "be on S3" do
40
+ assert true
41
+ end
42
+
43
+ should "generate a tempfile with the right name" do
44
+ file = @dummy.avatar.to_file
45
+ assert_match /^original.*\.png$/, File.basename(file.path)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,49 +1,20 @@
1
1
  require './test/helper'
2
2
  require 'aws/s3'
3
3
 
4
- class StorageTest < Test::Unit::TestCase
4
+ class S3Test < Test::Unit::TestCase
5
5
  def rails_env(env)
6
6
  silence_warnings do
7
7
  Object.const_set(:Rails, stub('Rails', :env => env))
8
8
  end
9
9
  end
10
10
 
11
- context "filesystem" do
12
- setup do
13
- rebuild_model :styles => { :thumbnail => "25x25#" }
14
- @dummy = Dummy.create!
15
-
16
- @dummy.avatar = File.open(File.join(File.dirname(__FILE__), "fixtures", "5k.png"))
17
- end
18
-
19
- should "allow file assignment" do
20
- assert @dummy.save
21
- end
22
-
23
- should "store the original" do
24
- @dummy.save
25
- assert File.exists?(@dummy.avatar.path)
26
- end
27
-
28
- should "store the thumbnail" do
29
- @dummy.save
30
- assert File.exists?(@dummy.avatar.path(:thumbnail))
31
- end
32
-
33
- should "clean up file objects" do
34
- File.stubs(:exist?).returns(true)
35
- Paperclip::Tempfile.any_instance.expects(:close).at_least_once()
36
- Paperclip::Tempfile.any_instance.expects(:unlink).at_least_once()
37
-
38
- @dummy.save!
39
- end
40
- end
41
-
42
11
  context "Parsing S3 credentials" do
43
12
  setup do
13
+ @proxy_settings = {:host => "127.0.0.1", :port => 8888, :user => "foo", :password => "bar"}
44
14
  AWS::S3::Base.stubs(:establish_connection!)
45
15
  rebuild_model :storage => :s3,
46
16
  :bucket => "testing",
17
+ :http_proxy => @proxy_settings,
47
18
  :s3_credentials => {:not => :important}
48
19
 
49
20
  @dummy = Dummy.new
@@ -68,6 +39,16 @@ class StorageTest < Test::Unit::TestCase
68
39
  rails_env("not really an env")
69
40
  assert_equal({:test => "12345"}, @avatar.parse_credentials(:test => "12345"))
70
41
  end
42
+
43
+ should "support HTTP proxy settings" do
44
+ rails_env("development")
45
+ assert_equal(true, @avatar.using_http_proxy?)
46
+ assert_equal(@proxy_settings[:host], @avatar.http_proxy_host)
47
+ assert_equal(@proxy_settings[:port], @avatar.http_proxy_port)
48
+ assert_equal(@proxy_settings[:user], @avatar.http_proxy_user)
49
+ assert_equal(@proxy_settings[:password], @avatar.http_proxy_password)
50
+ end
51
+
71
52
  end
72
53
 
73
54
  context "" do
@@ -117,7 +98,7 @@ class StorageTest < Test::Unit::TestCase
117
98
  }
118
99
 
119
100
  @dummy = Dummy.new
120
- @dummy.avatar = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
101
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
121
102
  end
122
103
 
123
104
  should "return a url containing the correct original file mime type" do
@@ -129,6 +110,27 @@ class StorageTest < Test::Unit::TestCase
129
110
  end
130
111
  end
131
112
 
113
+ context "An attachment that uses S3 for storage and has spaces in file name" do
114
+ setup do
115
+ AWS::S3::Base.stubs(:establish_connection!)
116
+ rebuild_model :styles => { :large => ['500x500#', :jpg] },
117
+ :storage => :s3,
118
+ :bucket => "bucket",
119
+ :path => ":attachment/:basename.:extension",
120
+ :s3_credentials => {
121
+ 'access_key_id' => "12345",
122
+ 'secret_access_key' => "54321"
123
+ }
124
+
125
+ @dummy = Dummy.new
126
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', 'spaced file.png'), 'rb')
127
+ end
128
+
129
+ should "return an escaped version of url" do
130
+ assert_match /.+\/spaced%20file\.png/, @dummy.avatar.url
131
+ end
132
+ end
133
+
132
134
  context "" do
133
135
  setup do
134
136
  AWS::S3::Base.stubs(:establish_connection!)
@@ -333,7 +335,7 @@ class StorageTest < Test::Unit::TestCase
333
335
 
334
336
  context "when assigned" do
335
337
  setup do
336
- @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
338
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
337
339
  @dummy = Dummy.new
338
340
  @dummy.avatar = @file
339
341
  end
@@ -362,7 +364,7 @@ class StorageTest < Test::Unit::TestCase
362
364
  File.stubs(:exist?).returns(true)
363
365
  Paperclip::Tempfile.any_instance.expects(:close).at_least_once()
364
366
  Paperclip::Tempfile.any_instance.expects(:unlink).at_least_once()
365
-
367
+
366
368
  @dummy.save!
367
369
  end
368
370
 
@@ -424,7 +426,7 @@ class StorageTest < Test::Unit::TestCase
424
426
 
425
427
  context "when assigned" do
426
428
  setup do
427
- @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
429
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
428
430
  @dummy = Dummy.new
429
431
  @dummy.avatar = @file
430
432
  end
@@ -459,7 +461,7 @@ class StorageTest < Test::Unit::TestCase
459
461
  rails_env('test')
460
462
 
461
463
  rebuild_model :storage => :s3,
462
- :s3_credentials => Pathname.new(File.join(File.dirname(__FILE__))).join("fixtures/s3.yml")
464
+ :s3_credentials => Pathname.new(File.join(File.dirname(__FILE__))).join("../fixtures/s3.yml")
463
465
 
464
466
  Dummy.delete_all
465
467
  @dummy = Dummy.new
@@ -481,7 +483,7 @@ class StorageTest < Test::Unit::TestCase
481
483
  rails_env('test')
482
484
 
483
485
  rebuild_model :storage => :s3,
484
- :s3_credentials => File.new(File.join(File.dirname(__FILE__), "fixtures/s3.yml"))
486
+ :s3_credentials => File.new(File.join(File.dirname(__FILE__), "../fixtures/s3.yml"))
485
487
 
486
488
  Dummy.delete_all
487
489
 
@@ -494,7 +496,7 @@ class StorageTest < Test::Unit::TestCase
494
496
  assert_equal 'env_secret', AWS::S3::Base.connection.options[:secret_access_key]
495
497
  end
496
498
  end
497
-
499
+
498
500
  context "S3 Permissions" do
499
501
  context "defaults to public-read" do
500
502
  setup do
@@ -509,7 +511,7 @@ class StorageTest < Test::Unit::TestCase
509
511
 
510
512
  context "when assigned" do
511
513
  setup do
512
- @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
514
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
513
515
  @dummy = Dummy.new
514
516
  @dummy.avatar = @file
515
517
  end
@@ -545,16 +547,16 @@ class StorageTest < Test::Unit::TestCase
545
547
  },
546
548
  :s3_permissions => 'private'
547
549
  end
548
-
550
+
549
551
  context "when assigned" do
550
552
  setup do
551
- @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
553
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
552
554
  @dummy = Dummy.new
553
555
  @dummy.avatar = @file
554
556
  end
555
-
557
+
556
558
  teardown { @file.close }
557
-
559
+
558
560
  context "and saved" do
559
561
  setup do
560
562
  AWS::S3::Base.stubs(:establish_connection!)
@@ -565,14 +567,14 @@ class StorageTest < Test::Unit::TestCase
565
567
  :access => 'private')
566
568
  @dummy.save
567
569
  end
568
-
570
+
569
571
  should "succeed" do
570
572
  assert true
571
573
  end
572
574
  end
573
575
  end
574
576
  end
575
-
577
+
576
578
  context "hash permissions set" do
577
579
  setup do
578
580
  rebuild_model :storage => :s3,
@@ -590,16 +592,16 @@ class StorageTest < Test::Unit::TestCase
590
592
  :thumb => 'public-read'
591
593
  }
592
594
  end
593
-
595
+
594
596
  context "when assigned" do
595
597
  setup do
596
- @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
598
+ @file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
597
599
  @dummy = Dummy.new
598
600
  @dummy.avatar = @file
599
601
  end
600
-
602
+
601
603
  teardown { @file.close }
602
-
604
+
603
605
  context "and saved" do
604
606
  setup do
605
607
  AWS::S3::Base.stubs(:establish_connection!)
@@ -612,57 +614,10 @@ class StorageTest < Test::Unit::TestCase
612
614
  end
613
615
  @dummy.save
614
616
  end
615
-
616
- should "succeed" do
617
- assert true
618
- end
619
- end
620
- end
621
- end
622
- end
623
-
624
- unless ENV["S3_TEST_BUCKET"].blank?
625
- context "Using S3 for real, an attachment with S3 storage" do
626
- setup do
627
- rebuild_model :styles => { :thumb => "100x100", :square => "32x32#" },
628
- :storage => :s3,
629
- :bucket => ENV["S3_TEST_BUCKET"],
630
- :path => ":class/:attachment/:id/:style.:extension",
631
- :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml"))
632
-
633
- Dummy.delete_all
634
- @dummy = Dummy.new
635
- end
636
-
637
- should "be extended by the S3 module" do
638
- assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
639
- end
640
-
641
- context "when assigned" do
642
- setup do
643
- @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
644
- @dummy.avatar = @file
645
- end
646
-
647
- teardown { @file.close }
648
-
649
- should "still return a Tempfile when sent #to_file" do
650
- assert_equal Paperclip::Tempfile, @dummy.avatar.to_file.class
651
- end
652
-
653
- context "and saved" do
654
- setup do
655
- @dummy.save
656
- end
657
617
 
658
- should "be on S3" do
618
+ should "succeed" do
659
619
  assert true
660
620
  end
661
-
662
- should "generate a tempfile with the right name" do
663
- file = @dummy.avatar.to_file
664
- assert_match /^original.*\.png$/, File.basename(file.path)
665
- end
666
621
  end
667
622
  end
668
623
  end
metadata CHANGED
@@ -1,144 +1,191 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: paperclip
3
- version: !ruby/object:Gem::Version
4
- version: 2.4.1
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
5
  prerelease:
6
+ segments:
7
+ - 2
8
+ - 4
9
+ - 2
10
+ version: 2.4.2
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Jon Yurek
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2011-09-07 00:00:00.000000000Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: activerecord
16
- requirement: &70313204575540 !ruby/object:Gem::Requirement
17
+
18
+ date: 2011-09-23 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ type: :runtime
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
17
24
  none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 2
31
+ - 3
32
+ - 0
21
33
  version: 2.3.0
34
+ version_requirements: *id001
35
+ name: activerecord
36
+ - !ruby/object:Gem::Dependency
22
37
  type: :runtime
23
38
  prerelease: false
24
- version_requirements: *70313204575540
25
- - !ruby/object:Gem::Dependency
26
- name: activesupport
27
- requirement: &70313204575020 !ruby/object:Gem::Requirement
39
+ requirement: &id002 !ruby/object:Gem::Requirement
28
40
  none: false
29
- requirements:
30
- - - ! '>='
31
- - !ruby/object:Gem::Version
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 7
45
+ segments:
46
+ - 2
47
+ - 3
48
+ - 2
32
49
  version: 2.3.2
50
+ version_requirements: *id002
51
+ name: activesupport
52
+ - !ruby/object:Gem::Dependency
33
53
  type: :runtime
34
54
  prerelease: false
35
- version_requirements: *70313204575020
36
- - !ruby/object:Gem::Dependency
37
- name: cocaine
38
- requirement: &70313204574560 !ruby/object:Gem::Requirement
55
+ requirement: &id003 !ruby/object:Gem::Requirement
39
56
  none: false
40
- requirements:
41
- - - ! '>='
42
- - !ruby/object:Gem::Version
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 27
61
+ segments:
62
+ - 0
63
+ - 0
64
+ - 2
43
65
  version: 0.0.2
66
+ version_requirements: *id003
67
+ name: cocaine
68
+ - !ruby/object:Gem::Dependency
44
69
  type: :runtime
45
70
  prerelease: false
46
- version_requirements: *70313204574560
47
- - !ruby/object:Gem::Dependency
48
- name: mime-types
49
- requirement: &70313204574180 !ruby/object:Gem::Requirement
50
- none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- type: :runtime
56
- prerelease: false
57
- version_requirements: *70313204574180
58
- - !ruby/object:Gem::Dependency
59
- name: shoulda
60
- requirement: &70313204573700 !ruby/object:Gem::Requirement
71
+ requirement: &id004 !ruby/object:Gem::Requirement
61
72
  none: false
62
- requirements:
63
- - - ! '>='
64
- - !ruby/object:Gem::Version
65
- version: '0'
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ version_requirements: *id004
81
+ name: mime-types
82
+ - !ruby/object:Gem::Dependency
66
83
  type: :development
67
84
  prerelease: false
68
- version_requirements: *70313204573700
69
- - !ruby/object:Gem::Dependency
70
- name: appraisal
71
- requirement: &70313204573280 !ruby/object:Gem::Requirement
85
+ requirement: &id005 !ruby/object:Gem::Requirement
72
86
  none: false
73
- requirements:
74
- - - ! '>='
75
- - !ruby/object:Gem::Version
76
- version: '0'
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ version_requirements: *id005
95
+ name: shoulda
96
+ - !ruby/object:Gem::Dependency
77
97
  type: :development
78
98
  prerelease: false
79
- version_requirements: *70313204573280
80
- - !ruby/object:Gem::Dependency
81
- name: mocha
82
- requirement: &70313204572860 !ruby/object:Gem::Requirement
99
+ requirement: &id006 !ruby/object:Gem::Requirement
83
100
  none: false
84
- requirements:
85
- - - ! '>='
86
- - !ruby/object:Gem::Version
87
- version: '0'
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ hash: 3
105
+ segments:
106
+ - 0
107
+ version: "0"
108
+ version_requirements: *id006
109
+ name: appraisal
110
+ - !ruby/object:Gem::Dependency
88
111
  type: :development
89
112
  prerelease: false
90
- version_requirements: *70313204572860
91
- - !ruby/object:Gem::Dependency
92
- name: aws-s3
93
- requirement: &70313204572440 !ruby/object:Gem::Requirement
113
+ requirement: &id007 !ruby/object:Gem::Requirement
94
114
  none: false
95
- requirements:
96
- - - ! '>='
97
- - !ruby/object:Gem::Version
98
- version: '0'
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ hash: 3
119
+ segments:
120
+ - 0
121
+ version: "0"
122
+ version_requirements: *id007
123
+ name: mocha
124
+ - !ruby/object:Gem::Dependency
99
125
  type: :development
100
126
  prerelease: false
101
- version_requirements: *70313204572440
102
- - !ruby/object:Gem::Dependency
103
- name: sqlite3
104
- requirement: &70313204572020 !ruby/object:Gem::Requirement
127
+ requirement: &id008 !ruby/object:Gem::Requirement
105
128
  none: false
106
- requirements:
107
- - - ! '>='
108
- - !ruby/object:Gem::Version
109
- version: '0'
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ hash: 3
133
+ segments:
134
+ - 0
135
+ version: "0"
136
+ version_requirements: *id008
137
+ name: aws-s3
138
+ - !ruby/object:Gem::Dependency
110
139
  type: :development
111
140
  prerelease: false
112
- version_requirements: *70313204572020
113
- - !ruby/object:Gem::Dependency
114
- name: cucumber
115
- requirement: &70313204571600 !ruby/object:Gem::Requirement
141
+ requirement: &id009 !ruby/object:Gem::Requirement
116
142
  none: false
117
- requirements:
118
- - - ! '>='
119
- - !ruby/object:Gem::Version
120
- version: '0'
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ hash: 3
147
+ segments:
148
+ - 0
149
+ version: "0"
150
+ version_requirements: *id009
151
+ name: sqlite3
152
+ - !ruby/object:Gem::Dependency
121
153
  type: :development
122
154
  prerelease: false
123
- version_requirements: *70313204571600
124
- - !ruby/object:Gem::Dependency
125
- name: capybara
126
- requirement: &70313204571180 !ruby/object:Gem::Requirement
155
+ requirement: &id010 !ruby/object:Gem::Requirement
127
156
  none: false
128
- requirements:
129
- - - ! '>='
130
- - !ruby/object:Gem::Version
131
- version: '0'
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ hash: 3
161
+ segments:
162
+ - 0
163
+ version: "0"
164
+ version_requirements: *id010
165
+ name: cucumber
166
+ - !ruby/object:Gem::Dependency
132
167
  type: :development
133
168
  prerelease: false
134
- version_requirements: *70313204571180
169
+ requirement: &id011 !ruby/object:Gem::Requirement
170
+ none: false
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ hash: 3
175
+ segments:
176
+ - 0
177
+ version: "0"
178
+ version_requirements: *id011
179
+ name: capybara
135
180
  description: Easy upload management for ActiveRecord
136
181
  email: jyurek@thoughtbot.com
137
182
  executables: []
183
+
138
184
  extensions: []
139
- extra_rdoc_files:
185
+
186
+ extra_rdoc_files:
140
187
  - README.md
141
- files:
188
+ files:
142
189
  - README.md
143
190
  - LICENSE
144
191
  - Rakefile
@@ -178,6 +225,7 @@ files:
178
225
  - test/fixtures/bad.png
179
226
  - test/fixtures/fog.yml
180
227
  - test/fixtures/s3.yml
228
+ - test/fixtures/spaced file.png
181
229
  - test/fixtures/text.txt
182
230
  - test/fixtures/twopage.pdf
183
231
  - test/fixtures/uppercase.PNG
@@ -194,7 +242,9 @@ files:
194
242
  - test/paperclip_missing_attachment_styles_test.rb
195
243
  - test/paperclip_test.rb
196
244
  - test/processor_test.rb
197
- - test/storage_test.rb
245
+ - test/storage/filesystem_test.rb
246
+ - test/storage/s3_live_test.rb
247
+ - test/storage/s3_test.rb
198
248
  - test/style_test.rb
199
249
  - test/thumbnail_test.rb
200
250
  - test/upfile_test.rb
@@ -205,32 +255,37 @@ files:
205
255
  - shoulda_macros/paperclip.rb
206
256
  homepage: https://github.com/thoughtbot/paperclip
207
257
  licenses: []
258
+
208
259
  post_install_message:
209
- rdoc_options:
260
+ rdoc_options:
210
261
  - --line-numbers
211
262
  - --inline-source
212
- require_paths:
263
+ require_paths:
213
264
  - lib
214
- required_ruby_version: !ruby/object:Gem::Requirement
265
+ required_ruby_version: !ruby/object:Gem::Requirement
215
266
  none: false
216
- requirements:
217
- - - ! '>='
218
- - !ruby/object:Gem::Version
219
- version: '0'
220
- segments:
267
+ requirements:
268
+ - - ">="
269
+ - !ruby/object:Gem::Version
270
+ hash: 3
271
+ segments:
221
272
  - 0
222
- hash: -1991530113411237677
223
- required_rubygems_version: !ruby/object:Gem::Requirement
273
+ version: "0"
274
+ required_rubygems_version: !ruby/object:Gem::Requirement
224
275
  none: false
225
- requirements:
226
- - - ! '>='
227
- - !ruby/object:Gem::Version
228
- version: '0'
229
- requirements:
276
+ requirements:
277
+ - - ">="
278
+ - !ruby/object:Gem::Version
279
+ hash: 3
280
+ segments:
281
+ - 0
282
+ version: "0"
283
+ requirements:
230
284
  - ImageMagick
231
285
  rubyforge_project: paperclip
232
- rubygems_version: 1.8.6
286
+ rubygems_version: 1.8.10
233
287
  signing_key:
234
288
  specification_version: 3
235
289
  summary: File attachments as attributes for ActiveRecord
236
290
  test_files: []
291
+