public
Description: Paperclip File Management Plugin
Homepage: http://www.thoughtbot.com/projects/paperclip
Clone URL: git://github.com/thoughtbot/paperclip.git
Paperclip error thrown on assign, not when attachment declared. Added 
:s3_domain_url and :s3_path_url for differing S3 URL styles. Added 
s3_protocol for using http over https.
jyurek (author)
Thu Aug 21 08:08:35 -0700 2008
commit  715ff88ac856b1561e63eafa08a3ddce85d3c514
tree    35c658e09a8e5dd791c122799724574d455428ee
parent  2a1583617b1132c4486b665a038e6ae185fe16e4
...
113
114
115
116
117
118
119
120
121
122
123
124
...
113
114
115
 
 
 
 
 
 
116
117
118
0
@@ -113,12 +113,6 @@ module Paperclip
0
     def has_attached_file name, options = {}
0
       include InstanceMethods
0
 
0
- %w(file_name).each do |field|
0
- unless column_names.include?("#{name}_#{field}")
0
- raise PaperclipError.new("#{self} model does not have required column '#{name}_#{field}'")
0
- end
0
- end
0
-
0
       write_inheritable_attribute(:attachment_definitions, {}) if attachment_definitions.nil?
0
       attachment_definitions[name] = {:validations => []}.merge(options)
0
 
...
53
54
55
 
 
 
 
 
 
56
57
58
...
53
54
55
56
57
58
59
60
61
62
63
64
0
@@ -53,6 +53,12 @@ module Paperclip
0
     # In addition to form uploads, you can also assign another Paperclip attachment:
0
     # new_user.avatar = old_user.avatar
0
     def assign uploaded_file
0
+ %w(file_name).each do |field|
0
+ unless @instance.class.column_names.include?("#{name}_#{field}")
0
+ raise PaperclipError.new("#{self} model does not have required column '#{name}_#{field}'")
0
+ end
0
+ end
0
+
0
       if uploaded_file.is_a?(Paperclip::Attachment)
0
         uploaded_file = uploaded_file.to_file(:original)
0
       end
...
85
86
87
 
 
 
88
89
90
 
 
 
 
 
91
92
93
...
97
98
99
100
101
102
103
104
 
 
 
 
 
 
105
106
107
 
 
 
 
 
108
109
110
...
132
133
134
 
 
 
 
135
136
137
...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
...
105
106
107
 
 
 
 
 
108
109
110
111
112
113
114
 
 
115
116
117
118
119
120
121
122
...
144
145
146
147
148
149
150
151
152
153
0
@@ -85,9 +85,17 @@ module Paperclip
0
     # policies that S3 provides (more information can be found here:
0
     # http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html#RESTCannedAccessPolicies)
0
     # The default for Paperclip is "public-read".
0
+ # * +s3_protocol+: The protocol for the URLs generated to your S3 assets. Can be either
0
+ # 'http' or 'https'. Defaults to 'http' when your :s3_permissions are 'public-read' (the
0
+ # default), and 'https' when your :s3_permissions are anything else.
0
     # * +bucket+: This is the name of the S3 bucket that will store your files. Remember
0
     # that the bucket must be unique across all of Amazon S3. If the bucket does not exist
0
     # Paperclip will attempt to create it. The bucket name will not be interpolated.
0
+ # * +url+: There are two options for the S3 url. You can choose to have the bucket's name
0
+ # placed domain-style (bucket.s3.amazonaws.com) or path-style (s3.amazonaws.com/bucket).
0
+ # Normally, this won't matter in the slightest and you can leave the default (which is
0
+ # path-style, or :s3_path_url). But in some cases paths don't work and you need to use
0
+ # the domain-style (:s3_domain_url). Anything else here will be treated like path-style.
0
     # * +path+: This is the key under the bucket in which the file will be stored. The
0
     # URL will be constructed from the bucket and the path. This is what you will want
0
     # to interpolate. Keys should be unique, like filenames, and despite the fact that
0
@@ -97,14 +105,18 @@ module Paperclip
0
       def self.extended base
0
         require 'right_aws'
0
         base.instance_eval do
0
- @bucket = @options[:bucket]
0
- @s3_credentials = parse_credentials(@options[:s3_credentials])
0
- @s3_options = @options[:s3_options] || {}
0
- @s3_permissions = @options[:s3_permissions] || 'public-read'
0
- @url = ":s3_url"
0
+ @bucket = @options[:bucket]
0
+ @s3_credentials = parse_credentials(@options[:s3_credentials])
0
+ @s3_options = @options[:s3_options] || {}
0
+ @s3_permissions = @options[:s3_permissions] || 'public-read'
0
+ @s3_protocol = @options[:s3_protocol] || (@s3_permissions == 'public-read' ? 'http' : 'https')
0
+ @url = ":s3_path_url" unless @url.to_s.match(/^s3.*url$/)
0
         end
0
- base.class.interpolations[:s3_url] = lambda do |attachment, style|
0
- "https://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}"
0
+ base.class.interpolations[:s3_path_url] = lambda do |attachment, style|
0
+ "#{attachment.s3_protocol}://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}"
0
+ end
0
+ base.class.interpolations[:s3_domain_url] = lambda do |attachment, style|
0
+ "#{attachment.s3_protocol}://#{attachment.bucket_name}.s3.amazonaws.com/#{attachment.path(style).gsub(%r{^/}, "")}"
0
         end
0
         ActiveRecord::Base.logger.info("[paperclip] S3 Storage Initalized.")
0
       end
0
@@ -132,6 +144,10 @@ module Paperclip
0
         s3_bucket.key(path(style)) ? true : false
0
       end
0
 
0
+ def s3_protocol
0
+ @s3_protocol
0
+ end
0
+
0
       # Returns representation of the data of the file assigned to the given
0
       # style, in the format most representative of the current storage.
0
       def to_file style = default_style
...
148
149
150
151
152
153
154
155
156
157
158
159
160
 
 
 
161
162
163
164
165
 
 
 
 
 
 
 
166
167
168
169
 
 
170
171
172
173
174
175
176
 
 
 
177
178
179
 
180
181
182
183
184
 
185
186
187
...
190
191
192
193
 
194
195
196
197
 
198
199
200
201
202
 
203
204
205
206
207
 
 
208
209
210
...
212
213
214
215
 
216
217
218
...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
...
244
245
246
247
248
 
 
249
250
251
...
279
280
281
282
283
284
285
 
 
 
 
286
287
288
...
148
149
150
 
 
 
 
 
 
 
 
 
 
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
 
 
168
169
170
171
172
173
 
 
 
174
175
176
177
178
 
179
180
181
182
183
 
184
185
186
187
...
190
191
192
 
193
194
195
196
 
197
198
199
200
201
 
202
203
204
205
 
 
206
207
208
209
210
...
212
213
214
 
215
216
217
218
...
221
222
223
 
 
 
 
 
 
 
 
 
224
225
226
...
235
236
237
 
 
238
239
240
241
242
...
270
271
272
 
 
 
 
273
274
275
276
277
278
279
0
@@ -148,40 +148,40 @@ class AttachmentTest < Test::Unit::TestCase
0
         :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
0
       })
0
       FileUtils.rm_rf("tmp")
0
- @instance = stub
0
- @instance.stubs(:id).returns(41)
0
- @instance.stubs(:class).returns(Dummy)
0
- @instance.stubs(:[]).with(:test_file_name).returns(nil)
0
- @instance.stubs(:[]).with(:test_content_type).returns(nil)
0
- @instance.stubs(:[]).with(:test_file_size).returns(nil)
0
- @instance.stubs(:[]).with(:test_updated_at).returns(nil)
0
- @instance.stubs(:logger).returns(ActiveRecord::Base.logger)
0
- @attachment = Paperclip::Attachment.new(:test,
0
- @instance)
0
+ rebuild_model
0
+ @instance = Dummy.new
0
+ @attachment = Paperclip::Attachment.new(:avatar, @instance)
0
       @file = File.new(File.join(File.dirname(__FILE__),
0
                                  "fixtures",
0
                                  "5k.png"))
0
     end
0
 
0
+ should "raise if there are not the correct columns when you try to assign" do
0
+ @other_attachment = Paperclip::Attachment.new(:not_here, @instance)
0
+ assert_raises(Paperclip::PaperclipError) do
0
+ @other_attachment.assign(@file)
0
+ end
0
+ end
0
+
0
     should "return its default_url when no file assigned" do
0
       assert @attachment.to_file.nil?
0
- assert_equal "/tests/original/missing.png", @attachment.url
0
- assert_equal "/tests/blah/missing.png", @attachment.url(:blah)
0
+ assert_equal "/avatars/original/missing.png", @attachment.url
0
+ assert_equal "/avatars/blah/missing.png", @attachment.url(:blah)
0
     end
0
     
0
     context "with a file assigned in the database" do
0
       setup do
0
- @instance.stubs(:[]).with(:test_file_name).returns("5k.png")
0
- @instance.stubs(:[]).with(:test_content_type).returns("image/png")
0
- @instance.stubs(:[]).with(:test_file_size).returns(12345)
0
+ @instance.stubs(:[]).with(:avatar_file_name).returns("5k.png")
0
+ @instance.stubs(:[]).with(:avatar_content_type).returns("image/png")
0
+ @instance.stubs(:[]).with(:avatar_file_size).returns(12345)
0
         now = Time.now
0
         Time.stubs(:now).returns(now)
0
- @instance.stubs(:[]).with(:test_updated_at).returns(Time.now)
0
+ @instance.stubs(:[]).with(:avatar_updated_at).returns(Time.now)
0
       end
0
 
0
       should "return a correct url even if the file does not exist" do
0
         assert_nil @attachment.to_file
0
- assert_match %r{^/tests/41/blah/5k\.png}, @attachment.url(:blah)
0
+ assert_match %r{^/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah)
0
       end
0
 
0
       should "make sure the updated_at mtime is in the url if it is defined" do
0
@@ -190,21 +190,21 @@ class AttachmentTest < Test::Unit::TestCase
0
 
0
       context "with the updated_at field removed" do
0
         setup do
0
- @instance.stubs(:[]).with(:test_updated_at).returns(nil)
0
+ @instance.stubs(:[]).with(:avatar_updated_at).returns(nil)
0
         end
0
 
0
         should "only return the url without the updated_at when sent #url" do
0
- assert_match "/tests/41/blah/5k.png", @attachment.url(:blah)
0
+ assert_match "/avatars/#{@instance.id}/blah/5k.png", @attachment.url(:blah)
0
         end
0
       end
0
 
0
       should "return the proper path when filename has a single .'s" do
0
- assert_equal "./test/../tmp/tests/dummies/original/41/5k.png", @attachment.path
0
+ assert_equal "./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.png", @attachment.path
0
       end
0
 
0
       should "return the proper path when filename has multiple .'s" do
0
- @instance.stubs(:[]).with(:test_file_name).returns("5k.old.png")
0
- assert_equal "./test/../tmp/tests/dummies/original/41/5k.old.png", @attachment.path
0
+ @instance.stubs(:[]).with(:avatar_file_name).returns("5k.old.png")
0
+ assert_equal "./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.old.png", @attachment.path
0
       end
0
 
0
       context "when expecting three styles" do
0
@@ -212,7 +212,7 @@ class AttachmentTest < Test::Unit::TestCase
0
           styles = {:styles => { :large => ["400x400", :png],
0
                                  :medium => ["100x100", :gif],
0
                                  :small => ["32x32#", :jpg]}}
0
- @attachment = Paperclip::Attachment.new(:test,
0
+ @attachment = Paperclip::Attachment.new(:avatar,
0
                                                   @instance,
0
                                                   styles)
0
         end
0
@@ -221,15 +221,6 @@ class AttachmentTest < Test::Unit::TestCase
0
           setup do
0
             now = Time.now
0
             Time.stubs(:now).returns(now)
0
- @instance.expects(:[]=).with(:test_file_name,
0
- File.basename(@file.path))
0
- @instance.expects(:[]=).with(:test_content_type, "image/png")
0
- @instance.expects(:[]=).with(:test_file_size, @file.size)
0
- @instance.expects(:[]=).with(:test_file_name, nil)
0
- @instance.expects(:[]=).with(:test_content_type, nil)
0
- @instance.expects(:[]=).with(:test_file_size, nil)
0
- @instance.expects(:[]=).with(:test_updated_at, nil)
0
- @instance.expects(:[]=).with(:test_updated_at, now)
0
             @attachment.assign(@file)
0
           end
0
 
0
@@ -244,8 +235,8 @@ class AttachmentTest < Test::Unit::TestCase
0
 
0
             should "return the real url" do
0
               assert @attachment.to_file
0
- assert_match %r{^/tests/41/original/5k\.png}, @attachment.url
0
- assert_match %r{^/tests/41/small/5k\.jpg}, @attachment.url(:small)
0
+ assert_match %r{^/avatars/#{@instance.id}/original/5k\.png}, @attachment.url
0
+ assert_match %r{^/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small)
0
             end
0
 
0
             should "commit the files to disk" do
0
@@ -279,10 +270,10 @@ class AttachmentTest < Test::Unit::TestCase
0
                 @existing_names = @attachment.styles.keys.collect do |style|
0
                   @attachment.path(style)
0
                 end
0
- @instance.expects(:[]=).with(:test_file_name, nil)
0
- @instance.expects(:[]=).with(:test_content_type, nil)
0
- @instance.expects(:[]=).with(:test_file_size, nil)
0
- @instance.expects(:[]=).with(:test_updated_at, nil)
0
+ @instance.expects(:[]=).with(:avatar_file_name, nil)
0
+ @instance.expects(:[]=).with(:avatar_content_type, nil)
0
+ @instance.expects(:[]=).with(:avatar_file_size, nil)
0
+ @instance.expects(:[]=).with(:avatar_updated_at, nil)
0
                 @attachment.assign nil
0
                 @attachment.save
0
               end
...
7
8
9
10
11
 
 
12
13
14
...
7
8
9
 
 
10
11
12
13
14
0
@@ -7,8 +7,8 @@ class PaperclipTest < Test::Unit::TestCase
0
       @file = File.new(File.join(FIXTURES_DIR, "5k.png"))
0
     end
0
 
0
- should "error when trying to also create a 'blah' attachment" do
0
- assert_raises(Paperclip::PaperclipError) do
0
+ should "not error when trying to also create a 'blah' attachment" do
0
+ assert_nothing_raised do
0
         Dummy.class_eval do
0
           has_attached_file :blah
0
         end
...
71
72
73
74
 
75
76
77
...
71
72
73
 
74
75
76
77
0
@@ -71,7 +71,7 @@ class StorageTest < Test::Unit::TestCase
0
       should "not get a bucket to get a URL" do
0
         @dummy.avatar.expects(:s3).never
0
         @dummy.avatar.expects(:s3_bucket).never
0
- assert_match %r{^https://s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url
0
+ assert_match %r{^http://s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url
0
       end
0
 
0
       context "and saved" do

Comments

    No one has commented yet.