Class: Technoweenie::AttachmentFu::Backends::FileSystemBackend

Inherits:
BackendDelegator
  • Object
show all
Defined in:
lib/technoweenie/attachment_fu/backends/file_system_backend.rb

Overview

Methods for file system backed attachments

Instance Attribute Summary

Attributes inherited from BackendDelegator

#attachment_options

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BackendDelegator

#__getobj__, #initialize

Constructor Details

This class inherits a constructor from Technoweenie::AttachmentFu::Backends::BackendDelegator

Class Method Details

.included_in_base(base) ⇒ Object



9
10
# File 'lib/technoweenie/attachment_fu/backends/file_system_backend.rb', line 9

def self.included_in_base(base)
end

Instance Method Details

#attachment_path_idObject

The attachment ID used in the full path of a file



31
32
33
# File 'lib/technoweenie/attachment_fu/backends/file_system_backend.rb', line 31

def attachment_path_id
  ((respond_to?(:parent_id) && parent_id) || read_attribute(:id)) || 0
end

#base_pathObject

Used as the base path that #public_filename strips off full_filename to create the public path



26
27
28
# File 'lib/technoweenie/attachment_fu/backends/file_system_backend.rb', line 26

def base_path
  @base_path ||= Rails.root.join('public').to_s
end

#current_dataObject



119
120
121
# File 'lib/technoweenie/attachment_fu/backends/file_system_backend.rb', line 119

def current_data
  File.file?(full_filename) ? File.read(full_filename) : nil
end

#destroy_fileObject

Destroys the file. Called in the after_destroy callback



86
87
88
89
90
91
92
93
# File 'lib/technoweenie/attachment_fu/backends/file_system_backend.rb', line 86

def destroy_file
  FileUtils.rm full_filename
  # remove directory also if it is now empty
  Dir.rmdir(File.dirname(full_filename)) if (Dir.entries(File.dirname(full_filename))-['.','..']).empty?
rescue
  logger.info "Exception destroying  #{full_filename.inspect}: [#{$!.class.name}] #{$1.to_s}"
  logger.warn $!.backtrace.collect { |b| " > #{b}" }.join("\n")
end

#full_filename(thumbnail = nil) ⇒ Object

Gets the full path to the filename in this format:

# This assumes a model name like MyModel
# public/#{table_name} is the default filesystem path
RAILS_ROOT/public/my_models/5/blah.jpg

Overwrite this method in your model to customize the filename. The optional thumbnail argument will output the thumbnail’s filename.



20
21
22
23
# File 'lib/technoweenie/attachment_fu/backends/file_system_backend.rb', line 20

def full_filename(thumbnail = nil)
  file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix].to_s
  Rails.root.join(file_system_path, *partitioned_path(thumbnail_name_for(thumbnail))).to_s
end

#notify_renameObject



81
82
83
# File 'lib/technoweenie/attachment_fu/backends/file_system_backend.rb', line 81

def notify_rename
  @old_filename = full_filename unless filename.nil? || @old_filename
end

#partitioned_path(*args) ⇒ Object

Partitions the given path into an array of path components.

For example, given an *args of [“foo”, “bar”], it will return ["0000", "0001", "foo", "bar"] (assuming that that id returns 1).

If the id is not an integer, then path partitioning will be performed by hashing the string value of the id with SHA-512, and splitting the result into 4 components. If the id a 128-bit UUID (as set by :uuid_primary_key => true) then it will be split into 2 components.

To turn this off entirely, set :partition => false.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/technoweenie/attachment_fu/backends/file_system_backend.rb', line 46

def partitioned_path(*args)
  if respond_to?(:attachment_options) && attachment_options[:partition] == false
    args
  elsif attachment_options[:uuid_primary_key]
    # Primary key is a 128-bit UUID in hex format. Split it into 2 components.
    path_id = attachment_path_id.to_s
    component1 = path_id[0..15] || "-"
    component2 = path_id[16..-1] || "-"
    [component1, component2] + args
  else
    path_id = attachment_path_id
    if path_id.is_a?(Integer)
      partitioned_path_for_fixnum(path_id, args)
    else
      # Primary key is a String. Hash it, then split it into 4 components.
      hash = Digest::SHA512.hexdigest(path_id.to_s)
      [hash[0..31], hash[32..63], hash[64..95], hash[96..127]] + args
    end
  end
end

#partitioned_path_for_fixnum(path_id, args) ⇒ Object



67
68
69
70
71
72
73
# File 'lib/technoweenie/attachment_fu/backends/file_system_backend.rb', line 67

def partitioned_path_for_fixnum(path_id, args)
  if path_id <= 9999_9999
    ("%08d" % path_id).scan(/..../) + args
  else
    ("%012d" % path_id).scan(/..../) + args
  end
end

#public_filename(thumbnail = nil) ⇒ Object

Gets the public path to the file The optional thumbnail argument will output the thumbnail’s filename.



77
78
79
# File 'lib/technoweenie/attachment_fu/backends/file_system_backend.rb', line 77

def public_filename(thumbnail = nil)
  full_filename(thumbnail).gsub %r(^#{Regexp.escape(base_path)}), ''
end

#rename_fileObject

Renames the given file before saving



96
97
98
99
100
101
102
103
104
105
# File 'lib/technoweenie/attachment_fu/backends/file_system_backend.rb', line 96

def rename_file
  return unless @old_filename && @old_filename != full_filename
  if save_attachment? && File.exists?(@old_filename)
    FileUtils.rm @old_filename
  elsif File.exists?(@old_filename)
    FileUtils.mv @old_filename, full_filename
  end
  @old_filename =  nil
  true
end

#save_to_storageObject

Saves the file to the file system



108
109
110
111
112
113
114
115
116
117
# File 'lib/technoweenie/attachment_fu/backends/file_system_backend.rb', line 108

def save_to_storage
  if save_attachment?
    # TODO: This overwrites the file if it exists, maybe have an allow_overwrite option?
    FileUtils.mkdir_p(File.dirname(full_filename))
    FileUtils.cp(temp_path, full_filename)
    FileUtils.chmod(attachment_options[:chmod] || 0644, full_filename)
  end
  @old_filename = nil
  true
end