patshaughnessy / paperclip forked from thoughtbot/paperclip

Forked to store files in a database table

This URL has Read+Write access

paperclip / lib / paperclip / storage.rb
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 1 module Paperclip
2 module Storage
3
5fdf9640 » jyurek 2008-05-15 Updated documentation. 4 # The default place to store attachments is in the filesystem. Files on the local
5 # filesystem can be very easily served by Apache without requiring a hit to your app.
6 # They also can be processed more easily after they've been saved, as they're just
7 # normal files. There is one Filesystem-specific option for has_attached_file.
8 # * +path+: The location of the repository of attachments on disk. This can (and, in
9 # almost all cases, should) be coordinated with the value of the +url+ option to
10 # allow files to be saved into a place where Apache can serve them without
11 # hitting your app. Defaults to
38ab6030 » bradly 2008-07-15 Changed the default path li... 12 # ":rails_root/public/:attachment/:id/:style/:basename.:extension"
5fdf9640 » jyurek 2008-05-15 Updated documentation. 13 # By default this places the files in the app's public directory which can be served
14 # directly. If you are using capistrano for deployment, a good idea would be to
15 # make a symlink to the capistrano-created system directory from inside your app's
16 # public directory.
17 # See Paperclip::Attachment#interpolate for more information on variable interpolaton.
081b8888 » jyurek 2008-11-06 Removed :filename interpola... 18 # :path => "/var/app/attachments/:class/:id/:style/:basename.:extension"
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 19 module Filesystem
20 def self.extended base
21 end
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 22
23 def exists?(style = default_style)
1fcf1d7e » mvanholstyn 2008-04-21 Fixed bug when exists? call... 24 if original_filename
25 File.exist?(path(style))
26 else
27 false
28 end
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 29 end
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 30
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 31 # Returns representation of the data of the file assigned to the given
32 # style, in the format most representative of the current storage.
33 def to_file style = default_style
9c510875 » jyurek 2008-12-10 #58 Applied Rob Anderton's ... 34 @queued_for_write[style] || (File.new(path(style), 'rb') if exists?(style))
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 35 end
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 36 alias_method :to_io, :to_file
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 37
38 def flush_writes #:nodoc:
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 39 @queued_for_write.each do |style, file|
3cc7ab7d » jyurek 2008-12-30 Applied patch from Rob Ande... 40 file.close
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 41 FileUtils.mkdir_p(File.dirname(path(style)))
a1b39cc6 » jyurek 2009-03-17 Reverted the nil assignment... 42 logger.info("[paperclip] saving #{path(style)}")
5eff51c5 » jyurek 2008-12-02 Converted the file copy on ... 43 FileUtils.mv(file.path, path(style))
8fce8150 » jyurek 2008-12-05 Fixed permission bug when m... 44 FileUtils.chmod(0644, path(style))
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 45 end
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 46 @queued_for_write = {}
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 47 end
48
49 def flush_deletes #:nodoc:
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 50 @queued_for_delete.each do |path|
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 51 begin
a1b39cc6 » jyurek 2009-03-17 Reverted the nil assignment... 52 logger.info("[paperclip] deleting #{path}")
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 53 FileUtils.rm(path) if File.exist?(path)
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 54 rescue Errno::ENOENT => e
87bd86cc » jyurek 2008-04-22 Resolved mvanholstyn's open... 55 # ignore file-not-found, let everything else pass
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 56 end
9324ba89 » jyurek 2008-12-29 Remove empty directories wh... 57 begin
58 while(true)
59 path = File.dirname(path)
60 FileUtils.rmdir(path)
61 end
54a18162 » jyurek 2009-02-07 Added Errno::EEXIST to the ... 62 rescue Errno::EEXIST, Errno::ENOTEMPTY, Errno::ENOENT, Errno::EINVAL, Errno::ENOTDIR
9324ba89 » jyurek 2008-12-29 Remove empty directories wh... 63 # Stop trying to remove parent directories
a23c21e9 » jyurek 2009-02-03 Unexpected system call erro... 64 rescue SystemCallError => e
65 logger.info("[paperclip] There was an unexpected error while deleting directories: #{e.class}")
66 # Ignore it
9324ba89 » jyurek 2008-12-29 Remove empty directories wh... 67 end
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 68 end
69 @queued_for_delete = []
70 end
71 end
72
5fdf9640 » jyurek 2008-05-15 Updated documentation. 73 # Amazon's S3 file hosting service is a scalable, easy place to store files for
74 # distribution. You can find out more about it at http://aws.amazon.com/s3
75 # There are a few S3-specific options for has_attached_file:
76 # * +s3_credentials+: Takes a path, a File, or a Hash. The path (or File) must point
77 # to a YAML file containing the +access_key_id+ and +secret_access_key+ that Amazon
78 # gives you. You can 'environment-space' this just like you do to your
79 # database.yml file, so different environments can use different accounts:
80 # development:
81 # access_key_id: 123...
82 # secret_access_key: 123...
83 # test:
84 # access_key_id: abc...
85 # secret_access_key: abc...
86 # production:
87 # access_key_id: 456...
88 # secret_access_key: 456...
89 # This is not required, however, and the file may simply look like this:
90 # access_key_id: 456...
91 # secret_access_key: 456...
7c598fbe » jyurek 2008-09-12 Documentation for buckets i... 92 # In which case, those access keys will be used in all environments. You can also
93 # put your bucket name in this file, instead of adding it to the code directly.
94 # This is useful when you want the same account but a different bucket for
95 # development versus production.
5fdf9640 » jyurek 2008-05-15 Updated documentation. 96 # * +s3_permissions+: This is a String that should be one of the "canned" access
97 # policies that S3 provides (more information can be found here:
98 # http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html#RESTCannedAccessPolicies)
99 # The default for Paperclip is "public-read".
715ff88a » jyurek 2008-08-21 Paperclip error thrown on a... 100 # * +s3_protocol+: The protocol for the URLs generated to your S3 assets. Can be either
101 # 'http' or 'https'. Defaults to 'http' when your :s3_permissions are 'public-read' (the
102 # default), and 'https' when your :s3_permissions are anything else.
96c800e4 » andrewtimberlake 2008-12-09 Added ability to set arbitr... 103 # * +s3_headers+: A hash of headers such as {'Expires' => 1.year.from_now.httpdate}
5fdf9640 » jyurek 2008-05-15 Updated documentation. 104 # * +bucket+: This is the name of the S3 bucket that will store your files. Remember
105 # that the bucket must be unique across all of Amazon S3. If the bucket does not exist
106 # Paperclip will attempt to create it. The bucket name will not be interpolated.
044f00ec » szajbus 2009-02-03 Added support for S3 bucket... 107 # You can define the bucket as a Proc if you want to determine it's name at runtime.
108 # Paperclip will call that Proc with attachment as the only argument.
5318f7dc » jyurek 2009-02-22 Fixed error in s3_alias_url... 109 # * +s3_host_alias+: The fully-qualified domain name (FQDN) that is the alias to the
110 # S3 domain of your bucket. Used with the :s3_alias_url url interpolation. See the
111 # link in the +url+ entry for more information about S3 domains and buckets.
723618a2 » jyurek 2009-02-22 S3 CNAME support 112 # * +url+: There are three options for the S3 url. You can choose to have the bucket's name
715ff88a » jyurek 2008-08-21 Paperclip error thrown on a... 113 # placed domain-style (bucket.s3.amazonaws.com) or path-style (s3.amazonaws.com/bucket).
723618a2 » jyurek 2009-02-22 S3 CNAME support 114 # Lastly, you can specify a CNAME (which requires the CNAME to be specified as
5318f7dc » jyurek 2009-02-22 Fixed error in s3_alias_url... 115 # :s3_alias_url. You can read more about CNAMEs and S3 at
723618a2 » jyurek 2009-02-22 S3 CNAME support 116 # http://docs.amazonwebservices.com/AmazonS3/latest/index.html?VirtualHosting.html
715ff88a » jyurek 2008-08-21 Paperclip error thrown on a... 117 # Normally, this won't matter in the slightest and you can leave the default (which is
118 # path-style, or :s3_path_url). But in some cases paths don't work and you need to use
119 # the domain-style (:s3_domain_url). Anything else here will be treated like path-style.
723618a2 » jyurek 2009-02-22 S3 CNAME support 120 # NOTE: If you use a CNAME for use with CloudFront, you can NOT specify https as your
121 # :s3_protocol; This is *not supported* by S3/CloudFront. Finally, when using the host
122 # alias, the :bucket parameter is ignored, as the hostname is used as the bucket name
123 # by S3.
5fdf9640 » jyurek 2008-05-15 Updated documentation. 124 # * +path+: This is the key under the bucket in which the file will be stored. The
125 # URL will be constructed from the bucket and the path. This is what you will want
126 # to interpolate. Keys should be unique, like filenames, and despite the fact that
127 # S3 (strictly speaking) does not support directories, you can still use a / to
128 # separate parts of your file name.
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 129 module S3
130 def self.extended base
131 require 'right_aws'
132 base.instance_eval do
715ff88a » jyurek 2008-08-21 Paperclip error thrown on a... 133 @s3_credentials = parse_credentials(@options[:s3_credentials])
ca481b4a » jyurek 2009-02-01 Formatting in storage.rb 134 @bucket = @options[:bucket] || @s3_credentials[:bucket]
044f00ec » szajbus 2009-02-03 Added support for S3 bucket... 135 @bucket = @bucket.call(self) if @bucket.is_a?(Proc)
ca481b4a » jyurek 2009-02-01 Formatting in storage.rb 136 @s3_options = @options[:s3_options] || {}
715ff88a » jyurek 2008-08-21 Paperclip error thrown on a... 137 @s3_permissions = @options[:s3_permissions] || 'public-read'
ca481b4a » jyurek 2009-02-01 Formatting in storage.rb 138 @s3_protocol = @options[:s3_protocol] || (@s3_permissions == 'public-read' ? 'http' : 'https')
139 @s3_headers = @options[:s3_headers] || {}
723618a2 » jyurek 2009-02-22 S3 CNAME support 140 @s3_host_alias = @options[:s3_host_alias]
7af82d25 » jyurek 2008-08-25 Typo fix in s3_url checking... 141 @url = ":s3_path_url" unless @url.to_s.match(/^:s3.*url$/)
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 142 end
723618a2 » jyurek 2009-02-22 S3 CNAME support 143 base.class.interpolations[:s3_alias_url] = lambda do |attachment, style|
144 "#{attachment.s3_protocol}://#{attachment.s3_host_alias}/#{attachment.path(style).gsub(%r{^/}, "")}"
145 end
715ff88a » jyurek 2008-08-21 Paperclip error thrown on a... 146 base.class.interpolations[:s3_path_url] = lambda do |attachment, style|
147 "#{attachment.s3_protocol}://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}"
148 end
149 base.class.interpolations[:s3_domain_url] = lambda do |attachment, style|
150 "#{attachment.s3_protocol}://#{attachment.bucket_name}.s3.amazonaws.com/#{attachment.path(style).gsub(%r{^/}, "")}"
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 151 end
152 end
153
dbd63a29 » jyurek 2008-04-29 Removed the need for S3 to ... 154 def s3
155 @s3 ||= RightAws::S3.new(@s3_credentials[:access_key_id],
156 @s3_credentials[:secret_access_key],
157 @s3_options)
158 end
159
160 def s3_bucket
161 @s3_bucket ||= s3.bucket(@bucket, true, @s3_permissions)
162 end
163
066c1069 » jyurek 2008-04-29 Added test to make sure no ... 164 def bucket_name
165 @bucket
166 end
167
723618a2 » jyurek 2009-02-22 S3 CNAME support 168 def s3_host_alias
169 @s3_host_alias
170 end
171
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 172 def parse_credentials creds
03e325bf » jyurek 2008-04-16 The :s3_credentials option ... 173 creds = find_credentials(creds).stringify_keys
174 (creds[ENV['RAILS_ENV']] || creds).symbolize_keys
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 175 end
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 176
177 def exists?(style = default_style)
dbd63a29 » jyurek 2008-04-29 Removed the need for S3 to ... 178 s3_bucket.key(path(style)) ? true : false
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 179 end
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 180
715ff88a » jyurek 2008-08-21 Paperclip error thrown on a... 181 def s3_protocol
182 @s3_protocol
183 end
184
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 185 # Returns representation of the data of the file assigned to the given
186 # style, in the format most representative of the current storage.
187 def to_file style = default_style
dbd63a29 » jyurek 2008-04-29 Removed the need for S3 to ... 188 @queued_for_write[style] || s3_bucket.key(path(style))
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 189 end
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 190 alias_method :to_io, :to_file
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 191
192 def flush_writes #:nodoc:
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 193 @queued_for_write.each do |style, file|
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 194 begin
a1b39cc6 » jyurek 2009-03-17 Reverted the nil assignment... 195 logger.info("[paperclip] saving #{path(style)}")
dbd63a29 » jyurek 2008-04-29 Removed the need for S3 to ... 196 key = s3_bucket.key(path(style))
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 197 key.data = file
96c800e4 » andrewtimberlake 2008-12-09 Added ability to set arbitr... 198 key.put(nil, @s3_permissions, {'Content-type' => instance_read(:content_type)}.merge(@s3_headers))
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 199 rescue RightAws::AwsError => e
200 raise
201 end
202 end
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 203 @queued_for_write = {}
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 204 end
205
206 def flush_deletes #:nodoc:
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 207 @queued_for_delete.each do |path|
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 208 begin
a1b39cc6 » jyurek 2009-03-17 Reverted the nil assignment... 209 logger.info("[paperclip] deleting #{path}")
dbd63a29 » jyurek 2008-04-29 Removed the need for S3 to ... 210 if file = s3_bucket.key(path)
465fba83 » mvanholstyn 2008-04-19 Do not hold open File/Tempf... 211 file.delete
212 end
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 213 rescue RightAws::AwsError
214 # Ignore this.
215 end
216 end
217 @queued_for_delete = []
218 end
03e325bf » jyurek 2008-04-16 The :s3_credentials option ... 219
220 def find_credentials creds
221 case creds
093f2193 » Tim Pope 2009-02-11 Syntax fix for 1.9 222 when File
03e325bf » jyurek 2008-04-16 The :s3_credentials option ... 223 YAML.load_file(creds.path)
093f2193 » Tim Pope 2009-02-11 Syntax fix for 1.9 224 when String
03e325bf » jyurek 2008-04-16 The :s3_credentials option ... 225 YAML.load_file(creds)
093f2193 » Tim Pope 2009-02-11 Syntax fix for 1.9 226 when Hash
03e325bf » jyurek 2008-04-16 The :s3_credentials option ... 227 creds
228 else
229 raise ArgumentError, "Credentials are not a path, file, or hash."
230 end
231 end
232 private :find_credentials
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 233
234 end
ee96901d » patshaughnessy 2009-02-19 Database storage 235
236 # Store files in a database.
237 #
238 # Usage is identical to the file system storage version, except:
239 #
240 # 1. In your model specify the "database" storage option; for example:
241 # has_attached_file :avatar, :storage => :database
242 #
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 243 # 2. The file will be stored in a column called [attachment name]_file (e.g. "avatar_file") by default.
ee96901d » patshaughnessy 2009-02-19 Database storage 244 #
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 245 # To specify a different column name, use :column, like this:
246 # has_attached_file :avatar, :storage => :database, :column => 'avatar_data'
247 #
248 # If you have defined different styles, these files will be stored in additional columns called
249 # [attachment name]_[style name]_file (e.g. "avatar_thumb_file") by default.
250 #
9556fab3 » patshaughnessy 2009-04-14 Updated comment/doc for dat... 251 # To specify different column names for styles, use :column in the style definition, like this:
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 252 # has_attached_file :avatar,
253 # :storage => :database,
254 # :styles => {
255 # :medium => {:geometry => "300x300>", :column => 'medium_file'},
256 # :thumb => {:geometry => "100x100>", :column => 'thumb_file'}
257 # }
258 #
9556fab3 » patshaughnessy 2009-04-14 Updated comment/doc for dat... 259 # 3. You need to create these new columns in your migrations or you'll get an exception. Example:
260 # add_column :users, :avatar_file, :binary
261 # add_column :users, :avatar_medium_file, :binary
262 # add_column :users, :avatar_thumb_file, :binary
ee96901d » patshaughnessy 2009-02-19 Database storage 263 #
9556fab3 » patshaughnessy 2009-04-14 Updated comment/doc for dat... 264 # Note the "binary" migration will not work for the LONGBLOB type in MySQL for the
265 # file_contents column. You may need to craft a SQL statement for your migration,
ee96901d » patshaughnessy 2009-02-19 Database storage 266 # depending on which database server you are using. Here's an example migration for MySQL:
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 267 # execute 'ALTER TABLE users ADD COLUMN avatar_file LONGBLOB'
268 # execute 'ALTER TABLE users ADD COLUMN avatar_medium_file LONGBLOB'
269 # execute 'ALTER TABLE users ADD COLUMN avatar_thumb_file LONGBLOB'
ee96901d » patshaughnessy 2009-02-19 Database storage 270 #
9556fab3 » patshaughnessy 2009-04-14 Updated comment/doc for dat... 271 # 4. To avoid performance problems loading all of the BLOB columns every time you access
272 # your ActiveRecord object, a class method is provided on your model called
273 # “select_without_file_columns_for.” This is set to a :select scope hash that will
274 # instruct ActiveRecord::Base.find to load all of the columns except the BLOB/file data columns.
275 #
276 # If you’re using Rails 2.3, you can specify this as a default scope:
277 # default_scope select_without_file_columns_for(:avatar)
278 #
279 # Or if you’re using Rails 2.1 or 2.2 you can use it to create a named scope:
280 # named_scope :without_file_data, select_without_file_columns_for(:avatar)
281 #
282 # 5. By default, URLs will be set to this pattern:
ee96901d » patshaughnessy 2009-02-19 Database storage 283 # /:relative_root/:class/:attachment/:id?style=:style
284 #
285 # Example:
286 # /app-root-url/users/avatars/23?style=original
287 #
288 # The idea here is that to retrieve a file from the database storage, you will need some
289 # controller's code to be executed.
290 #
291 # Once you pick a controller to use for downloading, you can add this line
292 # to generate the download action for the default URL/action (the plural attachment name),
293 # "avatars" in this example:
294 # downloads_files_for :user, :avatar
295 #
296 # Or you can write a download method manually if there are security, logging or other
297 # requirements.
298 #
299 # If you prefer a different URL for downloading files you can specify that in the model; e.g.:
300 # has_attached_file :avatar, :storage => :database, :url => '/users/show_avatar/:id/:style'
301 #
9556fab3 » patshaughnessy 2009-04-14 Updated comment/doc for dat... 302 # 6. Add a route for the download to the controller which will handle downloads, if necessary.
ee96901d » patshaughnessy 2009-02-19 Database storage 303 #
304 # The default URL, /:relative_root/:class/:attachment/:id?style=:style, will be matched by
305 # the default route: :controller/:action/:id
306 #
307 module Database
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 308 def self.extended base
ee96901d » patshaughnessy 2009-02-19 Database storage 309 base.instance_eval do
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 310 @file_columns = @options[:file_columns]
311 if @url == base.class.default_options[:url]
312 @url = ":relative_root/:class/:attachment/:id?style=:style"
313 end
ee96901d » patshaughnessy 2009-02-19 Database storage 314 end
315 base.class.interpolations[:relative_root] = lambda do |attachment, style|
316 begin
317 if ActionController::AbstractRequest.respond_to?(:relative_url_root)
318 relative_url_root = ActionController::AbstractRequest.relative_url_root
319 end
320 rescue NameError
321 end
322 if !relative_url_root && ActionController::Base.respond_to?(:relative_url_root)
52de311c » patshaughnessy 2009-03-11 Fix to relative_root interp... 323 relative_url_root = ActionController::Base.relative_url_root
ee96901d » patshaughnessy 2009-02-19 Database storage 324 end
52de311c » patshaughnessy 2009-03-11 Fix to relative_root interp... 325 relative_url_root
ee96901d » patshaughnessy 2009-02-19 Database storage 326 end
327 ActiveRecord::Base.logger.info("[paperclip] Database Storage Initalized.")
328 end
329
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 330 def column_for_style style
331 @file_columns[style.to_sym]
ee96901d » patshaughnessy 2009-02-19 Database storage 332 end
333
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 334 def instance_read_file(style)
335 column = column_for_style(style)
336 responds = instance.respond_to?(column)
337 cached = self.instance_variable_get("@_#{column}")
338 return cached if cached
339 # The blob attribute will not be present if select_without_file_columns_for was used
340 instance.reload :select => column if !instance.attribute_present?(column) && !instance.new_record?
341 instance.send(column) if responds
ee96901d » patshaughnessy 2009-02-19 Database storage 342 end
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 343
344 def instance_write_file(style, value)
345 setter = :"#{column_for_style(style)}="
346 responds = instance.respond_to?(setter)
347 self.instance_variable_set("@_#{setter.to_s.chop}", value)
348 instance.send(setter, value) if responds
ee96901d » patshaughnessy 2009-02-19 Database storage 349 end
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 350
351 def file_contents(style = default_style)
352 instance_read_file(style)
ee96901d » patshaughnessy 2009-02-19 Database storage 353 end
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 354 alias_method :data, :file_contents
355
ee96901d » patshaughnessy 2009-02-19 Database storage 356 def exists?(style = default_style)
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 357 !file_contents(style).nil?
ee96901d » patshaughnessy 2009-02-19 Database storage 358 end
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 359
ee96901d » patshaughnessy 2009-02-19 Database storage 360 # Returns representation of the data of the file assigned to the given
361 # style, in the format most representative of the current storage.
362 def to_file style = default_style
363 if @queued_for_write[style]
364 @queued_for_write[style]
365 elsif exists?(style)
366 tempfile = Tempfile.new instance_read(:file_name)
367 tempfile.write file_contents(style)
368 tempfile
369 else
370 nil
371 end
372 end
373 alias_method :to_io, :to_file
374
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 375 def path style = default_style
376 original_filename.nil? ? nil : column_for_style(style)
ee96901d » patshaughnessy 2009-02-19 Database storage 377 end
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 378
379 def assign uploaded_file
380
381 # Assign standard metadata attributes and perform post processing as usual
382 super
383
384 # Save the file contents for all styles in ActiveRecord immediately (before save)
385 @queued_for_write.each do |style, file|
386 instance_write_file(style, file.read)
387 end
ee96901d » patshaughnessy 2009-02-19 Database storage 388
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 389 # If we are assigning another Paperclip attachment, then fixup the
390 # filename and content type; necessary since Tempfile is used in to_file
391 if uploaded_file.is_a?(Paperclip::Attachment)
392 instance_write(:file_name, uploaded_file.instance_read(:file_name))
393 instance_write(:content_type, uploaded_file.instance_read(:content_type))
394 end
395 end
396
397 def queue_existing_for_delete
398 [:original, *@styles.keys].uniq.each do |style|
399 instance_write_file(style, nil)
400 end
401 instance_write(:file_name, nil)
402 instance_write(:content_type, nil)
403 instance_write(:file_size, nil)
404 instance_write(:updated_at, nil)
ee96901d » patshaughnessy 2009-02-19 Database storage 405 end
406
407 def flush_writes
408 @queued_for_write = {}
409 end
410
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 411 def flush_deletes
ee96901d » patshaughnessy 2009-02-19 Database storage 412 @queued_for_delete = []
413 end
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 414
ee96901d » patshaughnessy 2009-02-19 Database storage 415 module ControllerClassMethods
416 def self.included(base)
417 base.extend(self)
418 end
d96f1e48 » patshaughnessy 2009-04-13 Refactored to save files in... 419 def downloads_files_for(model, attachment)
ee96901d » patshaughnessy 2009-02-19 Database storage 420 define_method("#{attachment.to_s.pluralize}") do
421 model_record = Object.const_get(model.to_s.camelize.to_sym).find(params[:id])
422 style = params[:style] ? params[:style] : 'original'
423 send_data model_record.send(attachment).file_contents(style),
424 :filename => model_record.send("#{attachment}_file_name".to_sym),
425 :type => model_record.send("#{attachment}_content_type".to_sym)
426 end
427 end
428 end
429 end
430
34755c67 » jyurek 2008-04-06 Fixed the bug where files w... 431 end
432 end