public
Fork of halorgium/mephisto
Description: A mirror of the mephisto code-base
Homepage: http://mephistoblog.com/
Clone URL: git://github.com/technoweenie/mephisto.git
Click here to lend your support to: mephisto and make a donation at www.pledgie.com !
update attachment_fu plugin

git-svn-id: http://svn.techno-weenie.net/projects/mephisto/trunk@2687 
567b1171-46fb-0310-a4c9-b4bef9110e78
technoweenie (author)
Mon Jan 15 11:05:04 -0800 2007
commit  acdfa1e0a7c7c6ec43d53a00fbc59c9e7ec7e92c
tree    2648df93dae8de3b3f221466bd644b21e4768c35
parent  a7b0b1e5c8f378cce3ab6c084ebb3e5328c60138
...
1
2
3
4
 
 
 
5
6
7
8
9
 
 
 
10
11
12
13
14
15
 
 
 
...
1
 
 
 
2
3
4
5
6
 
 
 
7
8
9
10
11
 
 
 
12
13
14
15
0
@@ -1,14 +1,14 @@
0
 development:
0
- secret_access_key: AbCDEfGHiJKlmNOPQRS1
0
- access_key_id: 1234567891abcdeFGHI/JKL+MnoPQrsT123UvwX4
0
- bucket_prefix: appname_development
0
+ bucket_name: appname_development
0
+ access_key_id:
0
+ secret_access_key:
0
 
0
 test:
0
- secret_access_key: AbCDEfGHiJKlmNOPQRS1
0
- access_key_id: 1234567891abcdeFGHI/JKL+MnoPQrsT123UvwX4
0
- bucket_prefix: appname_test
0
+ bucket_name: appname_test
0
+ access_key_id:
0
+ secret_access_key:
0
 
0
 production:
0
- secret_access_key: AbCDEfGHiJKlmNOPQRS1
0
- access_key_id: 1234567891abcdeFGHI/JKL+MnoPQrsT123UvwX4
0
- bucket_prefix: appname
0
\ No newline at end of file
0
+ bucket_name: appname
0
+ access_key_id:
0
+ secret_access_key:
...
4
5
6
7
 
8
9
10
...
4
5
6
 
7
8
9
10
0
@@ -4,7 +4,7 @@ Tempfile.class_eval do
0
   # overwrite so tempfiles use the extension of the basename. important for rmagick and image science
0
   def make_tmpname(basename, n)
0
     ext = nil
0
- sprintf("%s%d-%d%s", basename.gsub(/\.\w+$/) { |s| ext = s; '' }, $$, n, ext)
0
+ sprintf("%s%d-%d%s", basename.to_s.gsub(/\.\w+$/) { |s| ext = s; '' }, $$, n, ext)
0
   end
0
 end
0
 
...
18
19
20
21
22
 
 
23
24
25
...
30
31
32
33
34
 
 
35
36
 
37
38
39
...
50
51
52
53
54
55
 
 
 
 
 
 
56
57
58
...
78
79
80
81
 
82
83
84
...
18
19
20
 
 
21
22
23
24
25
...
30
31
32
 
 
33
34
35
 
36
37
38
39
...
50
51
52
 
 
 
53
54
55
56
57
58
59
60
61
...
81
82
83
 
84
85
86
87
0
@@ -18,8 +18,8 @@ module Technoweenie # :nodoc:
0
       # * <tt>:resize_to</tt> - Used by RMagick to resize images. Pass either an array of width/height, or a geometry string.
0
       # * <tt>:thumbnails</tt> - Specifies a set of thumbnails to generate. This accepts a hash of filename suffixes and RMagick resizing options.
0
       # * <tt>:thumbnail_class</tt> - Set what class to use for thumbnails. This attachment class is used by default.
0
- # * <tt>:file_system_path</tt> - path to store the uploaded files. Uses public/#{table_name} by default.
0
- # Setting this sets the :storage to :file_system.
0
+ # * <tt>:path_prefix</tt> - path to store the uploaded files. Uses public/#{table_name} by default for the filesystem, and just #{table_name}
0
+ # for the S3 backend. Setting this sets the :storage to :file_system.
0
       # * <tt>:storage</tt> - Use :file_system to specify the attachment data is stored with the file system. Defaults to :db_system.
0
       #
0
       # Examples:
0
@@ -30,10 +30,10 @@ module Technoweenie # :nodoc:
0
       # has_attachment :content_type => :image, :resize_to => [50,50]
0
       # has_attachment :content_type => ['application/pdf', :image], :resize_to => 'x50'
0
       # has_attachment :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }
0
- # has_attachment :storage => :file_system, :file_system_path => 'public/files'
0
- # has_attachment :storage => :file_system, :file_system_path => 'public/files',
0
+ # has_attachment :storage => :file_system, :path_prefix => 'public/files'
0
+ # has_attachment :storage => :file_system, :path_prefix => 'public/files',
0
       # :content_type => :image, :resize_to => [50,50]
0
- # has_attachment :storage => :file_system, :file_system_path => 'public/files',
0
+ # has_attachment :storage => :file_system, :path_prefix => 'public/files',
0
       # :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }
0
       # has_attachment :storage => :s3
0
       def has_attachment(options = {})
0
@@ -50,9 +50,12 @@ module Technoweenie # :nodoc:
0
           class_inheritable_accessor :attachment_options
0
           attr_accessor :thumbnail_resize_options
0
 
0
- options[:storage] ||= options[:file_system_path] ? :file_system : :db_file
0
- options[:file_system_path] ||= File.join("public", table_name)
0
- options[:file_system_path] = options[:file_system_path][1..-1] if options[:file_system_path].first == '/'
0
+ options[:storage] ||= (options[:file_system_path] || options[:path_prefix]) ? :file_system : :db_file
0
+ options[:path_prefix] ||= options[:file_system_path]
0
+ if options[:path_prefix].nil?
0
+ options[:path_prefix] = options[:storage] == :s3 ? table_name : File.join("public", table_name)
0
+ end
0
+ options[:path_prefix] = options[:path_prefix][1..-1] if options[:path_prefix].first == '/'
0
 
0
           with_options :foreign_key => 'parent_id' do |m|
0
             m.has_many :thumbnails, :dependent => :destroy, :class_name => options[:thumbnail_class].to_s
0
@@ -78,7 +81,7 @@ module Technoweenie # :nodoc:
0
             else
0
               include Technoweenie::AttachmentFu::Processors.const_get("#{options[:processor].to_s.classify}")
0
           end
0
- before_save :process_attachment
0
+ after_validation :process_attachment
0
         end
0
         
0
         options[:content_type] = [options[:content_type]].flatten.collect { |t| t == :image ? Technoweenie::AttachmentFu.content_types : t }.flatten unless options[:content_type].nil?
...
16
17
18
19
 
20
21
22
...
16
17
18
 
19
20
21
22
0
@@ -16,7 +16,7 @@ module Technoweenie # :nodoc:
0
         # Overwrite this method in your model to customize the filename.
0
         # The optional thumbnail argument will output the thumbnail's filename.
0
         def full_filename(thumbnail = nil)
0
- file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:file_system_path].to_s
0
+ file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix].to_s
0
           File.join(RAILS_ROOT, file_system_path, attachment_path_id, thumbnail_name_for(thumbnail))
0
         end
0
       
...
3
4
5
6
 
7
8
9
10
 
11
12
13
14
15
16
 
17
18
19
 
20
21
22
23
24
25
 
 
 
26
27
28
29
30
 
 
 
31
32
33
34
35
 
 
 
36
37
 
38
39
40
41
 
42
43
44
45
 
 
 
 
 
 
 
 
 
46
47
 
48
49
 
50
51
52
...
56
57
58
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
61
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
64
65
66
 
 
67
68
 
 
69
70
 
71
72
 
73
74
75
76
77
78
 
79
80
81
82
 
 
 
 
 
 
 
 
 
83
84
85
 
86
87
88
89
90
91
92
93
94
95
 
 
 
 
 
 
 
 
 
 
 
96
97
98
99
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
102
 
 
 
 
 
103
104
 
105
106
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
109
110
111
112
113
 
 
 
 
 
 
 
 
 
 
 
 
 
114
115
116
117
 
118
119
 
120
121
 
122
123
124
 
 
 
 
 
 
 
 
 
 
125
126
127
128
129
 
130
131
 
 
 
 
 
 
 
 
 
 
132
133
134
...
3
4
5
 
6
7
8
9
 
10
11
12
13
14
15
 
16
17
18
 
19
20
21
22
 
 
 
23
24
25
26
27
 
 
 
28
29
30
31
32
 
 
 
33
34
35
36
 
37
38
39
40
 
41
42
43
44
 
45
46
47
48
49
50
51
52
53
54
 
55
56
 
57
58
59
60
...
64
65
66
 
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
 
 
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
 
 
 
117
118
119
120
121
122
123
124
125
126
 
127
128
129
130
131
132
 
133
134
135
 
 
136
137
138
139
140
141
142
143
144
145
 
 
146
147
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
 
205
206
207
208
209
210
 
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
 
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
 
266
267
 
268
269
 
270
271
272
 
273
274
275
276
277
278
279
280
281
282
283
284
285
 
 
286
287
 
288
289
290
291
292
293
294
295
296
297
298
299
300
0
@@ -3,50 +3,58 @@ module Technoweenie # :nodoc:
0
     module Backends
0
       # = AWS::S3 Storage Backend
0
       #
0
- # Enables use of Amazon's Simple Storage Service (http://aws.amazon.com/s3) as a storage mechanism
0
+ # Enables use of {Amazon's Simple Storage Service}[http://aws.amazon.com/s3] as a storage mechanism
0
       #
0
       # == Requirements
0
       #
0
- # Requires the AWS::S3 Library for S3 by Marcel Molina Jr. (http://amazon.rubyforge.org) installed either
0
+ # Requires the {AWS::S3 Library}[http://amazon.rubyforge.org] for S3 by Marcel Molina Jr. installed either
0
       # as a gem or a as a Rails plugin.
0
       #
0
       # == Configuration
0
       #
0
       # Configuration is done via <tt>RAILS_ROOT/config/amazon_s3.yml</tt> and is loaded according to the <tt>RAILS_ENV</tt>.
0
- # The minimum connection options that you must specify are your access key id and your secret access key.
0
+ # The minimum connection options that you must specify are a bucket name, your access key id and your secret access key.
0
       # If you don't already have your access keys, all you need to sign up for the S3 service is an account at Amazon.
0
       # You can sign up for S3 and get access keys by visiting http://aws.amazon.com/s3.
0
- #
0
+ #
0
       # Example configuration (RAILS_ROOT/config/amazon_s3.yml)
0
       #
0
       # development:
0
- # secret_access_key: AbCDEfGHiJKlmNOPQRS1
0
- # access_key_id: 1234567891abcdeFGHI/JKL+MnoPQrsT123UvwX4
0
- # bucket_prefix: appname_development
0
+ # bucket_name: appname_development
0
+ # access_key_id: <your key>
0
+ # secret_access_key: <your key>
0
       #
0
       # test:
0
- # secret_access_key: AbCDEfGHiJKlmNOPQRS1
0
- # access_key_id: 1234567891abcdeFGHI/JKL+MnoPQrsT123UvwX4
0
- # bucket_prefix: appname_test
0
+ # bucket_name: appname_test
0
+ # access_key_id: <your key>
0
+ # secret_access_key: <your key>
0
       #
0
       # production:
0
- # secret_access_key: AbCDEfGHiJKlmNOPQRS1
0
- # access_key_id: 1234567891abcdeFGHI/JKL+MnoPQrsT123UvwX4
0
- # bucket_prefix: appname
0
+ # bucket_name: appname
0
+ # access_key_id: <your key>
0
+ # secret_access_key: <your key>
0
       #
0
- # === Required arguments
0
+ # === Required configuration parameters
0
       #
0
       # * <tt>:access_key_id</tt> - The access key id for your S3 account. Provided by Amazon.
0
       # * <tt>:secret_access_key</tt> - The secret access key for your S3 account. Provided by Amazon.
0
- # * <tt>:bucket_prefix</tt> - The string prefix to assign to each bucket. Used to create unique bucket names in the format <tt>#{bucket_prefix}_#{table_name}</tt>.
0
+ # * <tt>:bucket_name</tt> - A unique bucket name (think of the bucket_name as being like a database name).
0
       #
0
       # If any of these required arguments is missing, a MissingAccessKey exception will be raised from AWS::S3.
0
       #
0
- # === Optional arguments
0
+ # == About bucket names
0
+ #
0
+ # Bucket names have to be globaly unique across the S3 system. And you can only have up to 100 of them,
0
+ # so it's a good idea to think of a bucket as being like a database, hence the correspondance in this
0
+ # implementation to the development, test, and production environments.
0
+ #
0
+ # The number of objects you can store in a bucket is, for all intents and purposes, unlimited.
0
+ #
0
+ # === Optional configuration parameters
0
       #
0
- # * <tt>:server</tt> - The server to make requests to. You can use this to specify your bucket in the subdomain, or your own domain's cname if you are using virtual hosted buckets. Defaults to <tt>s3.amazonaws.com</tt>.
0
+ # * <tt>:server</tt> - The server to make requests to. Defaults to <tt>s3.amazonaws.com</tt>.
0
       # * <tt>:port</tt> - The port to the requests should be made on. Defaults to 80 or 443 if <tt>:use_ssl</tt> is set.
0
- # * <tt>:use_ssl</tt> - Whether requests should be made over SSL. If set to true, <tt>:port</tt> will be implicitly set to 443, unless specified otherwise. Defaults to false.
0
+ # * <tt>:use_ssl</tt> - If set to true, <tt>:port</tt> will be implicitly set to 443, unless specified otherwise. Defaults to false.
0
       #
0
       # == Usage
0
       #
0
@@ -56,79 +64,237 @@ module Technoweenie # :nodoc:
0
       # has_attachment :storage => :s3
0
       # end
0
       #
0
- # Of course, all the usual configuration options apply:
0
+ # === Customizing the path
0
+ #
0
+ # By default, files are prefixed using a pseudo hierarchy in the form of <tt>:table_name/:id</tt>, which results
0
+ # in S3 urls that look like: http(s)://:server/:bucket_name/:table_name/:id/:filename with :table_name
0
+ # representing the customizable portion of the path. You can customize this prefix using the <tt>:path_prefix</tt>
0
+ # option:
0
+ #
0
+ # class Photo < ActiveRecord::Base
0
+ # has_attachment :storage => :s3, :path_prefix => 'my/custom/path'
0
+ # end
0
+ #
0
+ # Which would result in URLs like <tt>http(s)://:server/:bucket_name/my/custom/path/:id/:filename.</tt>
0
+ #
0
+ # === Permissions
0
+ #
0
+ # By default, files are stored on S3 with public access permissions. You can customize this using
0
+ # the <tt>:s3_access</tt> option to <tt>has_attachment</tt>. Available values are
0
+ # <tt>:private</tt>, <tt>:public_read_write</tt>, and <tt>:authenticated_read</tt>.
0
+ #
0
+ # === Other options
0
+ #
0
+ # Of course, all the usual configuration options apply, such as content_type and thumbnails:
0
+ #
0
+ # class Photo < ActiveRecord::Base
0
+ # has_attachment :storage => :s3, :content_type => ['application/pdf', :image], :resize_to => 'x50'
0
+ # has_attachment :storage => :s3, :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }
0
+ # end
0
+ #
0
+ # === Accessing S3 URLs
0
       #
0
- # has_attachment :storage => :s3, :content_type => ['application/pdf', :image], :resize_to => 'x50'
0
- # has_attachment :storage => :s3, :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }
0
+ # You can get an object's URL using the s3_url accessor. For example, assuming that for your postcard app
0
+ # you had a bucket name like 'postcard_world_development', and an attachment model called Photo:
0
+ #
0
+ # @postcard.s3_url # => http(s)://s3.amazonaws.com/postcard_world_development/photos/1/mexico.jpg
0
+ #
0
+ # The resulting url is in the form: http(s)://:server/:bucket_name/:table_name/:id/:file.
0
+ # The optional thumbnail argument will output the thumbnail's filename (if any).
0
+ #
0
+ # Additionally, you can get an object's base path relative to the bucket root using
0
+ # <tt>base_path</tt>:
0
+ #
0
+ # @photo.file_base_path # => photos/1
0
+ #
0
+ # And the full path (including the filename) using <tt>full_filename</tt>:
0
+ #
0
+ # @photo.full_filename # => photos/
0
+ #
0
+ # Niether <tt>base_path</tt> or <tt>full_filename</tt> include the bucket name as part of the path.
0
+ # You can retrieve the bucket name using the <tt>bucket_name</tt> method.
0
       module S3
0
- class S3RequiredLibraryNotFound < StandardError; end
0
- class S3ConfigFileNotFound < StandardError; end
0
- class S3BucketExists < StandardError; end
0
+ class S3RequiredLibraryNotFoundError < StandardError; end
0
+ class S3ConfigFileNotFoundError < StandardError; end
0
 
0
         def self.included(base) #:nodoc:
0
+ mattr_reader :bucket_name, :s3_config
0
+
0
           begin
0
             require 'aws/s3'
0
+ include AWS::S3
0
           rescue LoadError
0
- raise S3RequiredLibraryNotFound.new('AWS::S3 could not be loaded. Try installing with sudo gem i aws-s3, or see http://amazon.rubyforge.org for more information')
0
+ raise S3RequiredLibraryNotFoundError.new('AWS::S3 could not be loaded')
0
           end
0
 
0
           begin
0
             @@s3_config = YAML.load_file(RAILS_ROOT + '/config/amazon_s3.yml')[ENV['RAILS_ENV']].symbolize_keys
0
           rescue
0
- raise S3ConfigFileNotFound.new('File RAILS_ROOT/config/amazon_s3.yml not found')
0
+ raise S3ConfigFileNotFoundError.new('File RAILS_ROOT/config/amazon_s3.yml not found')
0
           end
0
 
0
- @@bucket = [@@s3_config.delete(:bucket_prefix), base.table_name].join('_')
0
- mattr_reader :s3_config, :bucket
0
+ @@bucket_name = s3_config[:bucket_name]
0
+
0
+ Base.establish_connection!(
0
+ :access_key_id => s3_config[:access_key_id],
0
+ :secret_access_key => s3_config[:secret_access_key],
0
+ :server => s3_config[:server],
0
+ :port => s3_config[:port],
0
+ :use_ssl => s3_config[:use_ssl]
0
+ )
0
 
0
- AWS::S3::Base.establish_connection!(s3_config)
0
- find_or_create_bucket(bucket)
0
+ # Bucket.create(@@bucket_name)
0
 
0
           base.before_update :rename_file
0
         end
0
-
0
- def self.find_or_create_bucket(name)
0
- AWS::S3::Bucket.find(name)
0
- rescue AWS::S3::NoSuchBucket
0
- AWS::S3::Bucket.create(name)
0
- rescue AWS::S3::AccessDenied
0
- raise S3BucketExists.new("Bucket name already exists: #{name}. Use a different bucket_prefix in RAILS_ROOT/config/amazon_s3.yml")
0
+
0
+ def self.protocol
0
+ @protocol ||= s3_config[:use_ssl] ? 'https://' : 'http://'
0
+ end
0
+
0
+ def self.hostname
0
+ @hostname ||= s3_config[:server] || AWS::S3::DEFAULT_HOST
0
+ end
0
+
0
+ def self.port_string
0
+ @port_string ||= s3_config[:port] ? ":#{s3_config[:port]}" : ''
0
         end
0
 
0
- # Generates an S3 URL for the file in the form of: http(s)://<tt>{server}</tt>/<tt>{bucket_name}</tt>/<tt>{file_name}</tt>
0
- # The <tt>{server}</tt> variable defaults to <tt>AWS::S3 URL::DEFAULT_HOST</tt> (http://s3.amazonaws.com) and can be
0
- # set using the configuration parameters in <tt>RAILS_ROOT/config/amazon_s3.yml</tt>
0
+ module ClassMethods
0
+ def s3_protocol
0
+ Technoweenie::AttachmentFu::Backends::S3.protocol
0
+ end
0
+
0
+ def s3_hostname
0
+ Technoweenie::AttachmentFu::Backends::S3.hostname
0
+ end
0
+
0
+ def s3_port_string
0
+ Technoweenie::AttachmentFu::Backends::S3.port_string
0
+ end
0
+ end
0
+
0
+ # Overwrites the base filename writer in order to store the old filename
0
+ def filename=(value)
0
+ @old_filename = filename unless filename.nil? || @old_filename
0
+ write_attribute :filename, sanitize_filename(value)
0
+ end
0
+
0
+ # The attachment ID used in the full path of a file
0
+ def attachment_path_id
0
+ ((respond_to?(:parent_id) && parent_id) || id).to_s
0
+ end
0
+
0
+ # The pseudo hierarchy containing the file relative to the bucket name
0
+ # Example: <tt>:table_name/:id</tt>
0
+ def base_path
0
+ File.join(attachment_options[:path_prefix], attachment_path_id)
0
+ end
0
+
0
+ # The full path to the file relative to the bucket name
0
+ # Example: <tt>:table_name/:id/:filename</tt>
0
+ def full_filename(thumbnail = nil)
0
+ File.join(base_path, thumbnail_name_for(thumbnail))
0
+ end
0
+
0
+ # All public objects are accessible via a GET request to the S3 servers. You can generate a
0
+ # url for an object using the s3_url method.
0
+ #
0
+ # @photo.s3_url
0
         #
0
- # Example usage: <tt>image_tag(@photo.s3_url)</tt>
0
+ # The resulting url is in the form: <tt>http(s)://:server/:bucket_name/:table_name/:id/:file</tt> where
0
+ # the <tt>:server</tt> variable defaults to <tt>AWS::S3 URL::DEFAULT_HOST</tt> (s3.amazonaws.com) and can be
0
+ # set using the configuration parameters in <tt>RAILS_ROOT/config/amazon_s3.yml</tt>.
0
+ #
0
+ # The optional thumbnail argument will output the thumbnail's filename (if any).
0
         def s3_url(thumbnail = nil)
0
- s3_config[:use_ssl] ? 'https://' : 'http://' + (s3_config[:server] || AWS::S3::DEFAULT_HOST) + '/' + bucket + '/' + thumbnail_name_for(thumbnail)
0
+ File.join(s3_protocol + s3_hostname + s3_port_string, bucket_name, full_filename(thumbnail))
0
         end
0
         alias :public_filename :s3_url
0
 
0
+ # All private objects are accessible via an authenticated GET request to the S3 servers. You can generate an
0
+ # authenticated url for an object like this:
0
+ #
0
+ # @photo.authenticated_s3_url
0
+ #
0
+ # By default authenticated urls expire 5 minutes after they were generated.
0
+ #
0
+ # Expiration options can be specified either with an absolute time using the <tt>:expires</tt> option,
0
+ # or with a number of seconds relative to now with the <tt>:expires_in</tt> option:
0
+ #
0
+ # # Absolute expiration date (October 13th, 2025)
0
+ # @photo.authenticated_s3_url(:expires => Time.mktime(2025,10,13).to_i)
0
+ #
0
+ # # Expiration in five hours from now
0
+ # @photo.authenticated_s3_url(:expires_in => 5.hours)
0
+ #
0
+ # You can specify whether the url should go over SSL with the <tt>:use_ssl</tt> option.
0
+ # By default, the ssl settings for the current connection will be used:
0
+ #
0
+ # @photo.authenticated_s3_url(:use_ssl => true)
0
+ #
0
+ # Finally, the optional thumbnail argument will output the thumbnail's filename (if any):
0
+ #
0
+ # @photo.authenticated_s3_url('thumbnail', :expires_in => 5.hours, :use_ssl => true)
0
+ def authenticated_s3_url(*args)
0
+ thumbnail = args.first.is_a?(String) ? args.first : nil
0
+ options = args.last.is_a?(Hash) ? args.last : {}
0
+ S3Object.url_for(full_filename(thumbnail), bucket_name, options)
0
+ end
0
+
0
         def create_temp_file
0
           write_to_temp_file current_data
0
         end
0
 
0
         def current_data
0
- AWS::S3::S3Object.value filename, bucket
0
+ S3Object.value full_filename, bucket_name
0
+ end
0
+
0
+ def s3_protocol
0
+ Technoweenie::AttachmentFu::Backends::S3.protocol
0
+ end
0
+
0
+ def s3_hostname
0
+ Technoweenie::AttachmentFu::Backends::S3.hostname
0
+ end
0
+
0
+ def s3_port_string
0
+ Technoweenie::AttachmentFu::Backends::S3.port_string
0
         end
0
 
0
         protected
0
- # Destroys the file. Called in the after_destroy callback
0
+ # Called in the after_destroy callback
0
           def destroy_file
0
- AWS::S3::S3Object.delete filename, bucket
0
+ S3Object.delete full_filename, bucket_name
0
           end
0
-
0
+
0
           def rename_file
0
             return unless @old_filename && @old_filename != filename
0
- AWS::S3::S3Object.rename(@old_filename, filename, bucket, :access => attachment_options[:s3_access])
0
+
0
+ old_full_filename = File.join(base_path, @old_filename)
0
+
0
+ S3Object.rename(
0
+ old_full_filename,
0
+ full_filename,
0
+ bucket_name,
0
+ :access => attachment_options[:s3_access]
0
+ )
0
+
0
             @old_filename = nil
0
             true
0
           end
0
-
0
- # Saves the file to S3
0
+
0
           def save_to_storage
0
- AWS::S3::S3Object.store(filename, temp_data, bucket, :content_type => content_type, :access => attachment_options[:s3_access]) if save_attachment?
0
+ if save_attachment?
0
+ S3Object.store(
0
+ full_filename,
0
+ temp_data,
0
+ bucket_name,
0
+ :content_type => content_type,
0
+ :access => attachment_options[:s3_access]
0
+ )
0
+ end
0
+
0
             @old_filename = nil
0
             true
0
           end
...
47
48
49
 
 
 
 
 
 
 
50
51
...
47
48
49
50
51
52
53
54
55
56
57
58
0
@@ -47,4 +47,11 @@ module BaseAttachmentTests
0
       end
0
     end
0
   end
0
+
0
+ def test_should_save_without_updating_file
0
+ attachment = upload_file :filename => '/files/foo.txt'
0
+ assert_valid attachment
0
+ assert !attachment.save_attachment?
0
+ assert_nothing_raised { attachment.save! }
0
+ end
0
 end
0
\ No newline at end of file
...
40
41
42
43
 
44
45
46
47
48
 
49
50
51
52
53
 
54
55
56
...
58
59
60
 
61
62
63
64
65
66
67
 
68
69
70
...
75
76
77
78
 
79
80
81
...
85
86
87
88
 
89
90
91
92
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
40
41
42
 
43
44
45
46
47
 
48
49
50
51
52
 
53
54
55
56
...
58
59
60
61
62
63
64
65
66
67
 
68
69
70
71
...
76
77
78
 
79
80
81
82
...
86
87
88
 
89
90
91
92
 
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
0
@@ -40,17 +40,17 @@ class ImageWithThumbsAttachment < Attachment
0
 end
0
 
0
 class FileAttachment < ActiveRecord::Base
0
- has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
0
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
0
   validates_as_attachment
0
 end
0
 
0
 class ImageFileAttachment < FileAttachment
0
- has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files',
0
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
0
     :content_type => :image, :resize_to => [50,50]
0
 end
0
 
0
 class ImageWithThumbsFileAttachment < FileAttachment
0
- has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files',
0
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
0
     :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }, :resize_to => [55,55]
0
   after_resize do |record, img|
0
     record.aspect_ratio = img.columns.to_f / img.rows.to_f
0
@@ -58,13 +58,14 @@ class ImageWithThumbsFileAttachment < FileAttachment
0
 end
0
 
0
 class ImageWithThumbsClassFileAttachment < FileAttachment
0
+ # use file_system_path to test backwards compatibility
0
   has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files',
0
     :thumbnails => { :thumb => [50, 50] }, :resize_to => [55,55],
0
     :thumbnail_class => 'ImageThumbnail'
0
 end
0
 
0
 class ImageThumbnail < FileAttachment
0
- has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files/thumbnails'
0
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files/thumbnails'
0
 end
0
 
0
 # no parent
0
@@ -75,7 +76,7 @@ end
0
 
0
 # no filename, no size, no content_type
0
 class MinimalAttachment < ActiveRecord::Base
0
- has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
0
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
0
   validates_as_attachment
0
   
0
   def filename
0
@@ -85,8 +86,21 @@ end
0
 
0
 begin
0
   class ImageScienceAttachment < ActiveRecord::Base
0
- has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files',
0
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
0
       :processor => :image_science, :thumbnails => { :thumb => [50, 51], :geometry => '31>' }, :resize_to => 55
0
   end
0
 rescue MissingSourceFile
0
-end
0
\ No newline at end of file
0
+end
0
+
0
+begin
0
+ class S3Attachment < ActiveRecord::Base
0
+ has_attachment :storage => :s3, :processor => :rmagick
0
+ validates_as_attachment
0
+ end
0
+
0
+ class S3WithPathPrefixAttachment < S3Attachment
0
+ has_attachment :storage => :s3, :path_prefix => 'some/custom/path/prefix', :processor => :rmagick
0
+ validates_as_attachment
0
+ end
0
+rescue Technoweenie::AttachmentFu::Backends::S3::S3ConfigFileNotFoundError
0
+end
...
49
50
51
 
 
 
 
 
 
 
 
 
 
 
 
52
53
...
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
0
@@ -49,4 +49,16 @@ ActiveRecord::Schema.define(:version => 0) do
0
   create_table :db_files, :force => true do |t|
0
     t.column :data, :binary
0
   end
0
+
0
+ create_table :s3_attachments, :force => true do |t|
0
+ t.column :parent_id, :integer
0
+ t.column :thumbnail, :string
0
+ t.column :filename, :string, :limit => 255
0
+ t.column :content_type, :string, :limit => 255
0
+ t.column :size, :integer
0
+ t.column :width, :integer
0
+ t.column :height, :integer
0
+ t.column :type, :string
0
+ t.column :aspect_ratio, :float
0
+ end
0
 end
0
\ No newline at end of file
...
1
2
 
 
3
4
5
...
1
2
3
4
5
6
7
0
@@ -1,5 +1,7 @@
0
 $:.unshift(File.dirname(__FILE__) + '/../lib')
0
 
0
+ENV['RAILS_ENV'] = 'test'
0
+
0
 require 'test/unit'
0
 require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
0
 require 'breakpoint'

Comments

    No one has commented yet.