paperclip 2.1.5 → 2.2.0

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.

@@ -0,0 +1,33 @@
1
+ module Paperclip
2
+ # This module is intended as a compatability shim for the differences in
3
+ # callbacks between Rails 2.0 and Rails 2.1.
4
+ module CallbackCompatability
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ base.send(:include, InstanceMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ # The implementation of this method is taken from the Rails 1.2.6 source,
12
+ # from rails/activerecord/lib/active_record/callbacks.rb, line 192.
13
+ def define_callbacks(*args)
14
+ args.each do |method|
15
+ self.class_eval <<-"end_eval"
16
+ def self.#{method}(*callbacks, &block)
17
+ callbacks << block if block_given?
18
+ write_inheritable_array(#{method.to_sym.inspect}, callbacks)
19
+ end
20
+ end_eval
21
+ end
22
+ end
23
+ end
24
+
25
+ module InstanceMethods
26
+ # The callbacks in < 2.1 don't worry about the extra options or the
27
+ # block, so just run what we have available.
28
+ def run_callbacks(meth, opts = nil, &blk)
29
+ callback(meth)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -30,7 +30,7 @@ module IOStream
30
30
  end
31
31
  end
32
32
 
33
- class IO
33
+ class IO #:nodoc:
34
34
  include IOStream
35
35
  end
36
36
 
@@ -0,0 +1,47 @@
1
+ module Paperclip
2
+ # Paperclip processors allow you to modify attached files when they are
3
+ # attached in any way you are able. Paperclip itself uses command-line
4
+ # programs for its included Thumbnail processor, but custom processors
5
+ # are not required to follow suit.
6
+ #
7
+ # Processors are required to be defined inside the Paperclip module and
8
+ # are also required to be a subclass of Paperclip::Processor. There are
9
+ # only two methods you must implement to properly be a subclass:
10
+ # #initialize and #make. Initialize's arguments are the file that will
11
+ # be operated on (which is an instance of File), and a hash of options
12
+ # that were defined in has_attached_file's style hash.
13
+ #
14
+ # All #make needs to do is return an instance of File (Tempfile is
15
+ # acceptable) which contains the results of the processing.
16
+ #
17
+ # See Paperclip.run for more information about using command-line
18
+ # utilities from within Processors.
19
+ class Processor
20
+ attr_accessor :file, :options
21
+
22
+ def initialize file, options = {}
23
+ @file = file
24
+ @options = options
25
+ end
26
+
27
+ def make
28
+ end
29
+
30
+ def self.make file, options = {}
31
+ new(file, options).make
32
+ end
33
+ end
34
+
35
+ # Due to how ImageMagick handles its image format conversion and how Tempfile
36
+ # handles its naming scheme, it is necessary to override how Tempfile makes
37
+ # its names so as to allow for file extensions. Idea taken from the comments
38
+ # on this blog post:
39
+ # http://marsorange.com/archives/of-mogrify-ruby-tempfile-dynamic-class-definitions
40
+ class Tempfile < ::Tempfile
41
+ # Replaces Tempfile's +make_tmpname+ with one that honors file extensions.
42
+ def make_tmpname(basename, n)
43
+ extension = File.extname(basename)
44
+ sprintf("%s,%d,%d%s", File.basename(basename, extension), $$, n, extension)
45
+ end
46
+ end
47
+ end
@@ -56,6 +56,14 @@ module Paperclip
56
56
  rescue Errno::ENOENT => e
57
57
  # ignore file-not-found, let everything else pass
58
58
  end
59
+ begin
60
+ while(true)
61
+ path = File.dirname(path)
62
+ FileUtils.rmdir(path)
63
+ end
64
+ rescue Errno::ENOTEMPTY, Errno::ENOENT, Errno::EINVAL
65
+ # Stop trying to remove parent directories
66
+ end
59
67
  end
60
68
  @queued_for_delete = []
61
69
  end
@@ -91,6 +99,7 @@ module Paperclip
91
99
  # * +s3_protocol+: The protocol for the URLs generated to your S3 assets. Can be either
92
100
  # 'http' or 'https'. Defaults to 'http' when your :s3_permissions are 'public-read' (the
93
101
  # default), and 'https' when your :s3_permissions are anything else.
102
+ # * +s3_headers+: A hash of headers such as {'Expires' => 1.year.from_now.httpdate}
94
103
  # * +bucket+: This is the name of the S3 bucket that will store your files. Remember
95
104
  # that the bucket must be unique across all of Amazon S3. If the bucket does not exist
96
105
  # Paperclip will attempt to create it. The bucket name will not be interpolated.
@@ -113,6 +122,7 @@ module Paperclip
113
122
  @s3_options = @options[:s3_options] || {}
114
123
  @s3_permissions = @options[:s3_permissions] || 'public-read'
115
124
  @s3_protocol = @options[:s3_protocol] || (@s3_permissions == 'public-read' ? 'http' : 'https')
125
+ @s3_headers = @options[:s3_headers] || {}
116
126
  @url = ":s3_path_url" unless @url.to_s.match(/^:s3.*url$/)
117
127
  end
118
128
  base.class.interpolations[:s3_path_url] = lambda do |attachment, style|
@@ -165,7 +175,7 @@ module Paperclip
165
175
  logger.info("[paperclip] -> #{path(style)}")
166
176
  key = s3_bucket.key(path(style))
167
177
  key.data = file
168
- key.put(nil, @s3_permissions, {'Content-type' => instance_read(:content_type)})
178
+ key.put(nil, @s3_permissions, {'Content-type' => instance_read(:content_type)}.merge(@s3_headers))
169
179
  rescue RightAws::AwsError => e
170
180
  raise
171
181
  end
@@ -1,33 +1,28 @@
1
1
  module Paperclip
2
2
  # Handles thumbnailing images that are uploaded.
3
- class Thumbnail
3
+ class Thumbnail < Processor
4
4
 
5
- attr_accessor :file, :current_geometry, :target_geometry, :format, :whiny_thumbnails, :convert_options
5
+ attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options
6
6
 
7
7
  # Creates a Thumbnail object set to work on the +file+ given. It
8
8
  # will attempt to transform the image into one defined by +target_geometry+
9
9
  # which is a "WxH"-style string. +format+ will be inferred from the +file+
10
10
  # unless specified. Thumbnail creation will raise no errors unless
11
- # +whiny_thumbnails+ is true (which it is, by default. If +convert_options+ is
11
+ # +whiny+ is true (which it is, by default. If +convert_options+ is
12
12
  # set, the options will be appended to the convert command upon image conversion
13
- def initialize file, target_geometry, format = nil, convert_options = nil, whiny_thumbnails = true
13
+ def initialize file, options = {}
14
+ super
15
+ geometry = options[:geometry]
14
16
  @file = file
15
- @crop = target_geometry[-1,1] == '#'
16
- @target_geometry = Geometry.parse target_geometry
17
- @current_geometry = Geometry.from_file file
18
- @convert_options = convert_options
19
- @whiny_thumbnails = whiny_thumbnails
17
+ @crop = geometry[-1,1] == '#'
18
+ @target_geometry = Geometry.parse geometry
19
+ @current_geometry = Geometry.from_file @file
20
+ @convert_options = options[:convert_options]
21
+ @whiny = options[:whiny].nil? ? true : options[:whiny]
22
+ @format = options[:format]
20
23
 
21
24
  @current_format = File.extname(@file.path)
22
25
  @basename = File.basename(@file.path, @current_format)
23
-
24
- @format = format
25
- end
26
-
27
- # Creates a thumbnail, as specified in +initialize+, +make+s it, and returns the
28
- # resulting Tempfile.
29
- def self.make file, dimensions, format = nil, convert_options = nil, whiny_thumbnails = true
30
- new(file, dimensions, format, convert_options, whiny_thumbnails).make
31
26
  end
32
27
 
33
28
  # Returns true if the +target_geometry+ is meant to crop.
@@ -56,7 +51,7 @@ module Paperclip
56
51
  begin
57
52
  success = Paperclip.run("convert", command.gsub(/\s+/, " "))
58
53
  rescue PaperclipCommandLineError
59
- raise PaperclipError, "There was an error processing the thumbnail for #{@basename}" if @whiny_thumbnails
54
+ raise PaperclipError, "There was an error processing the thumbnail for #{@basename}" if @whiny
60
55
  end
61
56
 
62
57
  dst
@@ -72,17 +67,4 @@ module Paperclip
72
67
  trans
73
68
  end
74
69
  end
75
-
76
- # Due to how ImageMagick handles its image format conversion and how Tempfile
77
- # handles its naming scheme, it is necessary to override how Tempfile makes
78
- # its names so as to allow for file extensions. Idea taken from the comments
79
- # on this blog post:
80
- # http://marsorange.com/archives/of-mogrify-ruby-tempfile-dynamic-class-definitions
81
- class Tempfile < ::Tempfile
82
- # Replaces Tempfile's +make_tmpname+ with one that honors file extensions.
83
- def make_tmpname(basename, n)
84
- extension = File.extname(basename)
85
- sprintf("%s,%d,%d%s", File.basename(basename, extension), $$, n, extension)
86
- end
87
- end
88
70
  end
@@ -1,5 +1,15 @@
1
1
  module Paperclip
2
+ # =Paperclip Shoulda Macros
3
+ #
4
+ # These macros are intended for use with shoulda, and will be included into
5
+ # your tests automatically. All of the macros use the standard shoulda
6
+ # assumption that the name of the test is based on the name of the model
7
+ # you're testing (that is, UserTest is the test for the User model), and
8
+ # will load that class for testing purposes.
2
9
  module Shoulda
10
+ # This will test whether you have defined your attachment correctly by
11
+ # checking for all the required fields exist after the definition of the
12
+ # attachment.
3
13
  def should_have_attached_file name, options = {}
4
14
  klass = self.name.gsub(/Test$/, '').constantize
5
15
  context "Class #{klass.name} with attachment #{name}" do
@@ -8,20 +18,131 @@ module Paperclip
8
18
  assert klass.instance_methods.include?(meth), "#{klass.name} does not respond to #{name}."
9
19
  end
10
20
  end
21
+ end
22
+ end
11
23
 
12
- should "have the correct definition" do
13
- expected = options
14
- actual = klass.attachment_definitions[name]
15
- expected.delete(:validations) if not options.key?(:validations)
16
- expected.delete(:whiny_thumbnails) if not options.key?(:whiny_thumbnails)
24
+ # Tests for validations on the presence of the attachment.
25
+ def should_validate_attachment_presence name
26
+ klass = self.name.gsub(/Test$/, '').constantize
27
+ context "Class #{klass.name} validating presence on #{name}" do
28
+ context "when the assignment is nil" do
29
+ setup do
30
+ @attachment = klass.new.send(name)
31
+ @attachment.assign(nil)
32
+ end
33
+ should "have a :presence validation error" do
34
+ assert @assignment.errors[:presence]
35
+ end
36
+ end
37
+ context "when the assignment is valid" do
38
+ setup do
39
+ @attachment = klass.new.send(name)
40
+ @attachment.assign(nil)
41
+ end
42
+ should "have a :presence validation error" do
43
+ assert ! @assignment.errors[:presence]
44
+ end
45
+ end
46
+ end
47
+ end
17
48
 
18
- assert_equal expected, actual
49
+ # Tests that you have content_type validations specified. There are two
50
+ # options, :valid and :invalid. Both accept an array of strings. The
51
+ # strings should be a list of content types which will pass and fail
52
+ # validation, respectively.
53
+ def should_validate_attachment_content_type name, options = {}
54
+ klass = self.name.gsub(/Test$/, '').constantize
55
+ valid = [options[:valid]].flatten
56
+ invalid = [options[:invalid]].flatten
57
+ context "Class #{klass.name} validating content_types on #{name}" do
58
+ valid.each do |type|
59
+ context "being assigned a file with a content_type of #{type}" do
60
+ setup do
61
+ @file = StringIO.new(".")
62
+ class << @file; attr_accessor :content_type; end
63
+ @file.content_type = type
64
+ @attachment = klass.new.send(name)
65
+ @attachment.assign(@file)
66
+ end
67
+ should "not have a :content_type validation error" do
68
+ assert ! @assignment.errors[:content_type]
69
+ end
70
+ end
19
71
  end
72
+ invalid.each do |type|
73
+ context "being assigned a file with a content_type of #{type}" do
74
+ setup do
75
+ @file = StringIO.new(".")
76
+ class << @file; attr_accessor :content_type; end
77
+ @file.content_type = type
78
+ @attachment = klass.new.send(name)
79
+ @attachment.assign(@file)
80
+ end
81
+ should "have a :content_type validation error" do
82
+ assert @assignment.errors[:content_type]
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ # Tests to ensure that you have file size validations turned on. You
90
+ # can pass the same options to this that you can to
91
+ # validate_attachment_file_size - :less_than, :greater_than, and :in.
92
+ # :less_than checks that a file is less than a certain size, :greater_than
93
+ # checks that a file is more than a certain size, and :in takes a Range or
94
+ # Array which specifies the lower and upper limits of the file size.
95
+ def should_validate_attachment_size name, options = {}
96
+ klass = self.name.gsub(/Test$/, '').constantize
97
+ min = options[:greater_than] || (options[:in] && options[:in].first) || 0
98
+ max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
99
+ range = (min..max)
100
+ context "Class #{klass.name} validating file size on #{name}" do
101
+ context "with an attachment that is #{max+1} bytes" do
102
+ setup do
103
+ @file = StringIO.new("." * (max+1))
104
+ @attachment = klass.new.send(name)
105
+ @attachment.assign(@file)
106
+ end
107
+
108
+ should "have a :size validation error" do
109
+ assert @attachment.errors[:size]
110
+ end
111
+ end
112
+ context "with an attachment that us #{max-1} bytes" do
113
+ setup do
114
+ @file = StringIO.new("." * (max-1))
115
+ @attachment = klass.new.send(name)
116
+ @attachment.assign(@file)
117
+ end
118
+
119
+ should "not have a :size validation error" do
120
+ assert ! @attachment.errors[:size]
121
+ end
122
+ end
123
+
124
+ if min > 0
125
+ context "with an attachment that is #{min-1} bytes" do
126
+ setup do
127
+ @file = StringIO.new("." * (min-1))
128
+ @attachment = klass.new.send(name)
129
+ @attachment.assign(@file)
130
+ end
131
+
132
+ should "have a :size validation error" do
133
+ assert @attachment.errors[:size]
134
+ end
135
+ end
136
+ context "with an attachment that us #{min+1} bytes" do
137
+ setup do
138
+ @file = StringIO.new("." * (min+1))
139
+ @attachment = klass.new.send(name)
140
+ @attachment.assign(@file)
141
+ end
20
142
 
21
- should "ensure that ImageMagick is available" do
22
- %w( convert identify ).each do |command|
23
- `#{Paperclip.path_for_command(command)}`
24
- assert_equal 0, $?, "ImageMagick's #{command} returned with an error. Make sure that #{command} is available at #{Paperclip.path_for_command(command)}"
143
+ should "not have a :size validation error" do
144
+ assert ! @attachment.errors[:size]
145
+ end
25
146
  end
26
147
  end
27
148
  end
@@ -81,6 +81,8 @@ class AttachmentTest < Test::Unit::TestCase
81
81
  @dummy.avatar = @file
82
82
  end
83
83
 
84
+ teardown { @file.close }
85
+
84
86
  should "make sure that they are interpolated correctly" do
85
87
  assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path
86
88
  end
@@ -99,6 +101,8 @@ class AttachmentTest < Test::Unit::TestCase
99
101
  @dummy.avatar = @file
100
102
  end
101
103
 
104
+ teardown { @file.close }
105
+
102
106
  should "return the proper path" do
103
107
  temporary_rails_env(@rails_env) {
104
108
  assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path
@@ -117,6 +121,7 @@ class AttachmentTest < Test::Unit::TestCase
117
121
  :thumb => "-thumbnailize"
118
122
  }
119
123
  @dummy = Dummy.new
124
+ @dummy.avatar
120
125
  end
121
126
 
122
127
  should "report the correct options when sent #extra_options_for(:thumb)" do
@@ -127,48 +132,128 @@ class AttachmentTest < Test::Unit::TestCase
127
132
  assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large)
128
133
  end
129
134
 
130
- context "when given a file" do
131
- setup do
132
- @file = File.new(File.join(File.dirname(__FILE__),
133
- "fixtures",
134
- "5k.png"), 'rb')
135
- Paperclip::Thumbnail.stubs(:make)
136
- [:thumb, :large].each do |style|
137
- @dummy.avatar.stubs(:extra_options_for).with(style)
138
- end
135
+ before_should "call extra_options_for(:thumb/:large)" do
136
+ Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb)
137
+ Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large)
138
+ end
139
+ end
140
+
141
+ context "An attachment with both 'normal' and hash-style styles" do
142
+ setup do
143
+ rebuild_model :styles => {
144
+ :normal => ["50x50#", :png],
145
+ :hash => { :geometry => "50x50#", :format => :png }
146
+ }
147
+ @dummy = Dummy.new
148
+ @attachment = @dummy.avatar
149
+ end
150
+
151
+ [:processors, :whiny, :convert_options, :geometry, :format].each do |field|
152
+ should "have the same #{field} field" do
153
+ assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field]
139
154
  end
155
+ end
156
+ end
140
157
 
141
- [:thumb, :large].each do |style|
142
- should "call extra_options_for(#{style})" do
143
- @dummy.avatar.expects(:extra_options_for).with(style)
144
- @dummy.avatar = @file
145
- end
158
+ context "An attachment with multiple processors" do
159
+ setup do
160
+ class Paperclip::Test < Paperclip::Processor; end
161
+ @style_params = { :once => {:one => 1, :two => 2} }
162
+ rebuild_model :processors => [:thumbnail, :test], :styles => @style_params
163
+ @dummy = Dummy.new
164
+ @file = StringIO.new("...")
165
+ @file.stubs(:to_tempfile).returns(@file)
166
+ Paperclip::Test.stubs(:make).returns(@file)
167
+ Paperclip::Thumbnail.stubs(:make).returns(@file)
168
+ end
169
+
170
+ context "when assigned" do
171
+ setup { @dummy.avatar = @file }
172
+
173
+ before_should "call #make on all specified processors" do
174
+ expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => nil, :convert_options => ""})
175
+ Paperclip::Thumbnail.expects(:make).with(@file, expected_params).returns(@file)
176
+ Paperclip::Test.expects(:make).with(@file, expected_params).returns(@file)
146
177
  end
147
178
  end
148
179
  end
149
180
 
181
+ context "Assigning an attachment with post_process hooks" do
182
+ setup do
183
+ rebuild_model :styles => { :something => "100x100#" }
184
+ Dummy.class_eval do
185
+ before_avatar_post_process :do_before_avatar
186
+ after_avatar_post_process :do_after_avatar
187
+ before_post_process :do_before_all
188
+ after_post_process :do_after_all
189
+ def do_before_avatar; end
190
+ def do_after_avatar; end
191
+ def do_before_all; end
192
+ def do_after_all; end
193
+ end
194
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
195
+ @file.stubs(:to_tempfile).returns(@file)
196
+ @dummy = Dummy.new
197
+ Paperclip::Thumbnail.stubs(:make).returns(@file)
198
+ @attachment = @dummy.avatar
199
+ end
200
+
201
+ should "call the defined callbacks when assigned" do
202
+ @dummy.expects(:do_before_avatar).with()
203
+ @dummy.expects(:do_after_avatar).with()
204
+ @dummy.expects(:do_before_all).with()
205
+ @dummy.expects(:do_after_all).with()
206
+ Paperclip::Thumbnail.expects(:make).returns(@file)
207
+ @dummy.avatar = @file
208
+ end
209
+
210
+ should "not cancel the processing if a before_post_process returns nil" do
211
+ @dummy.expects(:do_before_avatar).with().returns(nil)
212
+ @dummy.expects(:do_after_avatar).with()
213
+ @dummy.expects(:do_before_all).with().returns(nil)
214
+ @dummy.expects(:do_after_all).with()
215
+ Paperclip::Thumbnail.expects(:make).returns(@file)
216
+ @dummy.avatar = @file
217
+ end
218
+
219
+ should "cancel the processing if a before_post_process returns false" do
220
+ @dummy.expects(:do_before_avatar).never
221
+ @dummy.expects(:do_after_avatar).never
222
+ @dummy.expects(:do_before_all).with().returns(false)
223
+ @dummy.expects(:do_after_all).never
224
+ Paperclip::Thumbnail.expects(:make).never
225
+ @dummy.avatar = @file
226
+ end
227
+
228
+ should "cancel the processing if a before_avatar_post_process returns false" do
229
+ @dummy.expects(:do_before_avatar).with().returns(false)
230
+ @dummy.expects(:do_after_avatar).never
231
+ @dummy.expects(:do_before_all).with().returns(true)
232
+ @dummy.expects(:do_after_all).never
233
+ Paperclip::Thumbnail.expects(:make).never
234
+ @dummy.avatar = @file
235
+ end
236
+ end
237
+
150
238
  context "Assigning an attachment" do
151
239
  setup do
152
- rebuild_model
153
-
154
- @not_file = mock
155
- @not_file.stubs(:nil?).returns(false)
156
- @not_file.expects(:to_tempfile).returns(self)
157
- @not_file.expects(:original_filename).returns("filename.png\r\n")
158
- @not_file.expects(:content_type).returns("image/png\r\n")
159
- @not_file.expects(:size).returns(10).times(2)
160
-
240
+ rebuild_model :styles => { :something => "100x100#" }
241
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
242
+ @file.expects(:original_filename).returns("5k.png\n\n")
243
+ @file.expects(:content_type).returns("image/png\n\n")
244
+ @file.stubs(:to_tempfile).returns(@file)
161
245
  @dummy = Dummy.new
246
+ Paperclip::Thumbnail.expects(:make).returns(@file)
247
+ @dummy.expects(:run_callbacks).with(:before_avatar_post_process, {:original => @file})
248
+ @dummy.expects(:run_callbacks).with(:before_post_process, {:original => @file})
249
+ @dummy.expects(:run_callbacks).with(:after_avatar_post_process, {:original => @file, :something => @file})
250
+ @dummy.expects(:run_callbacks).with(:after_post_process, {:original => @file, :something => @file})
162
251
  @attachment = @dummy.avatar
163
- @attachment.expects(:valid_assignment?).with(@not_file).returns(true)
164
- @attachment.expects(:queue_existing_for_delete)
165
- @attachment.expects(:post_process)
166
- @attachment.expects(:validate)
167
- @dummy.avatar = @not_file
252
+ @dummy.avatar = @file
168
253
  end
169
254
 
170
255
  should "strip whitespace from original_filename field" do
171
- assert_equal "filename.png", @dummy.avatar.original_filename
256
+ assert_equal "5k.png", @dummy.avatar.original_filename
172
257
  end
173
258
 
174
259
  should "strip whitespace from content_type field" do
@@ -192,6 +277,7 @@ class AttachmentTest < Test::Unit::TestCase
192
277
  @attachment.expects(:valid_assignment?).with(@not_file).returns(true)
193
278
  @attachment.expects(:queue_existing_for_delete)
194
279
  @attachment.expects(:post_process)
280
+ @attachment.expects(:valid?).returns(true)
195
281
  @attachment.expects(:validate)
196
282
  @dummy.avatar = @not_file
197
283
  end
@@ -216,6 +302,8 @@ class AttachmentTest < Test::Unit::TestCase
216
302
  "5k.png"), 'rb')
217
303
  end
218
304
 
305
+ teardown { @file.close }
306
+
219
307
  should "raise if there are not the correct columns when you try to assign" do
220
308
  @other_attachment = Paperclip::Attachment.new(:not_here, @instance)
221
309
  assert_raises(Paperclip::PaperclipError) do
@@ -247,12 +335,16 @@ class AttachmentTest < Test::Unit::TestCase
247
335
 
248
336
  should "return a correct url even if the file does not exist" do
249
337
  assert_nil @attachment.to_file
250
- assert_match %r{^/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah)
338
+ assert_match %r{^/system/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah)
251
339
  end
252
340
 
253
341
  should "make sure the updated_at mtime is in the url if it is defined" do
254
342
  assert_match %r{#{Time.now.to_i}$}, @attachment.url(:blah)
255
343
  end
344
+
345
+ should "make sure the updated_at mtime is NOT in the url if false is passed to the url method" do
346
+ assert_no_match %r{#{Time.now.to_i}$}, @attachment.url(:blah, false)
347
+ end
256
348
 
257
349
  context "with the updated_at field removed" do
258
350
  setup do
@@ -302,8 +394,8 @@ class AttachmentTest < Test::Unit::TestCase
302
394
  should "return the real url" do
303
395
  file = @attachment.to_file
304
396
  assert file
305
- assert_match %r{^/avatars/#{@instance.id}/original/5k\.png}, @attachment.url
306
- assert_match %r{^/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small)
397
+ assert_match %r{^/system/avatars/#{@instance.id}/original/5k\.png}, @attachment.url
398
+ assert_match %r{^/system/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small)
307
399
  file.close
308
400
  end
309
401
 
@@ -378,6 +470,8 @@ class AttachmentTest < Test::Unit::TestCase
378
470
  @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
379
471
  end
380
472
 
473
+ teardown { @file.close }
474
+
381
475
  should "not error when assigned an attachment" do
382
476
  assert_nothing_raised { @dummy.avatar = @file }
383
477
  end