Module: CachedUploads::ClassMethods

Defined in:
lib/cached_uploads.rb

Instance Method Summary collapse

Instance Method Details

#clean_temporary_filesObject

Cleans out all temporary files older than the given age. Typically called by the controller.



109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/cached_uploads.rb', line 109

def clean_temporary_files
  cached_uploads.each do |file_attr, config|
    folder = send config[:tmp_folder_method]
    pattern = File.join folder, '*'
  
    Dir.glob(pattern).each do |path|
      if File.basename(path) != '.gitignore' and File.mtime(path) < config[:tmp_file_expiration].ago
        File.delete path
      end
    end
  end
end

#has_cached_upload(file_attr, options = {}) ⇒ Object

Reader and writer methods will be defined for the file_attr name.

CachedUploads looks for class and instance methods defining the permanent file path, the temporary file path, and the temporary file folder path. If the file attribute is for example #screenshot, then the path methods will be, respectively, #screenshot_path, #tmp_screenshot_path, and .tmp_screenshot folder. The names of those methods may be overridden–see the “Options” documentation below.

You may define the path methods like any normal instance method. For convenience and to keep all related code in one place, you may also pass Procs when you call .has_cached_uploads, and the methods will be defined for you using the Procs. For example, instead of explicitly defining a #screenshot_path method, you can do this:

has_cached_upload(:screenshot, {
  folder:   ->()    { File.join Rails.root, 'uploads/screenshots' },
  filename: ->(obj) { "#{obj.id}.png"                             }
})

CachedUploads will then automatically define #screenshot_path using the given folder and filename Procs.

You may also define an instance attribute storing the uploaded file’s extension. If file_attr is #screenshot, then by default the extension attribute is #screenshot_ext. If the class responds to the extension attribute, then that attribute will be set automatically when the file attribute’s writer is called. For example, if the file attribute is #screenshot, then calling #screenshot= will cause #screenshot_ext to be set.

Options:

  • folder: A Proc that returns an absolute path to the permanent files’ folder.

  • filename: A Proc that accepts an instance of the class and returns the permanent filename. Do not include the folder path in the returned value.

  • tmp_folder: Like folder, but for the temporary files.

  • tmp_filename: Like filename, but for the temporary files.

  • prm_path_method: Name of the instance method that returns the path to the permanent file. Defaults to “#{file_attr}_path”.

  • tmp_path_method: Name of the instance method that returns the path to the temporary file. Defaults to “tmp_#{file_attr}_path”.

  • tmp_folder_method: Name of the instance method that returns the path to the temporary files’ folder. Defaults to “tmp_#{file_attr}_folder”.

  • tmp_file_expiration: Optional. Length of time temporary files last before being cleaned out. Defaults to 48.hours.

  • ext_attr: Name of the instance attribute storing the file’s extension. Defaults to “#{file_attr}_ext”. CachedUploads does not define this method for you. Typically, this attribute would be a database column.

  • prm_md5_attr: Name of the instance attribute storing the permanent file’s MD5 hash. Defaults to “#{file_attr}_md5”. If this attribute exists, it should be a database column, but it need not exist at all.

  • tmp_md5_attr: Name of the instance attribute storing the temporary file’s MD5 hash. Defaults to “tmp_#{file_attr}_md5”. This attribute is typically not a database column. If you don’t define it yourself, CachedUploads will define it for you.

  • no_prm: If set to true, permanent files won’t be written to disk. You might want to use this if, for example, you’re hosting uploaded files on an external CDN. Options related to the permanent file have no effect when this option is true.



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
# File 'lib/cached_uploads.rb', line 190

def has_cached_upload(file_attr, options = {})
  # Set default configs.
  options.reverse_merge!(
    prm_path_method:     "#{file_attr}_path",
    tmp_path_method:     "tmp_#{file_attr}_path",
    tmp_folder_method:   "tmp_#{file_attr}_folder",
    tmp_file_expiration: 48.hours,
    ext_attr:            "#{file_attr}_ext",
    prm_md5_attr:        "#{file_attr}_md5",
    tmp_md5_attr:        "tmp_#{file_attr}_md5"
  )
  
  # Initialize the configs hash.
  self.cached_uploads ||= {}
  cached_uploads[file_attr.to_sym] = options
  
  # Define the reader for the file.
  attr_reader file_attr
  
  # Define the writer for the file.
  class_eval %Q(
    def #{file_attr}=(f)
      @#{file_attr} = f
      if respond_to?('#{options[:ext_attr]}=')
        self.#{options[:ext_attr]} = File.extname(f.original_filename)
      end
    end
  )
  
  # Define the accessor for the temporary file MD5 string. This should never be a
  # database column.
  unless method_defined? options[:tmp_md5_attr]
    attr_accessor options[:tmp_md5_attr]
  end
  
  # Define the path methods, if given.
  if options[:folder] and options[:filename]
    define_singleton_method "#{file_attr}_folder" do
      options[:folder].call self
    end
    
    define_method "#{file_attr}_filename" do
      options[:filename].call(self)
    end
    
    define_method "#{file_attr}_path" do
      File.join self.class.send("#{file_attr}_folder"), send("#{file_attr}_filename")
    end
  end
  
  # Define the temporary path methods, if given.
  if options[:tmp_folder] and options[:tmp_filename]
    define_singleton_method "tmp_#{file_attr}_folder" do
      options[:tmp_folder].call self
    end
    
    define_method "tmp_#{file_attr}_filename" do
      options[:tmp_filename].call(self)
    end
    
    define_method "tmp_#{file_attr}_path" do
      File.join self.class.send("tmp_#{file_attr}_folder"), send("tmp_#{file_attr}_filename")
    end
  end
  
  unless options[:no_prm]
    # Register the save callback.      
    after_save do |obj|
      obj.write_permanent_file file_attr
    end
  
    # Register the delete callback.
    after_destroy do |obj|
      obj.delete_permanent_file file_attr
    end
  end
  
  # Register the hash writer callback.
  before_save do |obj|
    obj.write_permanent_file_md5 file_attr
  end
end