]> projects.mako.cc - selectricity/blob - vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/file_system_backend.rb
464b9c778060088151d073b3abe487abf12d0608
[selectricity] / vendor / plugins / attachment_fu / lib / technoweenie / attachment_fu / backends / file_system_backend.rb
1 require 'ftools'
2 module Technoweenie # :nodoc:
3   module AttachmentFu # :nodoc:
4     module Backends
5       # Methods for file system backed attachments
6       module FileSystemBackend
7         def self.included(base) #:nodoc:
8           base.before_update :rename_file
9         end
10       
11         # Gets the full path to the filename in this format:
12         #
13         #   # This assumes a model name like MyModel
14         #   # public/#{table_name} is the default filesystem path 
15         #   RAILS_ROOT/public/my_models/5/blah.jpg
16         #
17         # Overwrite this method in your model to customize the filename.
18         # The optional thumbnail argument will output the thumbnail's filename.
19         def full_filename(thumbnail = nil)
20           file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix].to_s
21           File.join(RAILS_ROOT, file_system_path, *partitioned_path(thumbnail_name_for(thumbnail)))
22         end
23       
24         # Used as the base path that #public_filename strips off full_filename to create the public path
25         def base_path
26           @base_path ||= File.join(RAILS_ROOT, 'public')
27         end
28       
29         # The attachment ID used in the full path of a file
30         def attachment_path_id
31           ((respond_to?(:parent_id) && parent_id) || id).to_i
32         end
33       
34         # overrwrite this to do your own app-specific partitioning. 
35         # you can thank Jamis Buck for this: http://www.37signals.com/svn/archives2/id_partitioning.php
36         def partitioned_path(*args)
37           ("%08d" % attachment_path_id).scan(/..../) + args
38         end
39       
40         # Gets the public path to the file
41         # The optional thumbnail argument will output the thumbnail's filename.
42         def public_filename(thumbnail = nil)
43           full_filename(thumbnail).gsub %r(^#{Regexp.escape(base_path)}), ''
44         end
45       
46         def filename=(value)
47           @old_filename = full_filename unless filename.nil? || @old_filename
48           write_attribute :filename, sanitize_filename(value)
49         end
50
51         # Creates a temp file from the currently saved file.
52         def create_temp_file
53           copy_to_temp_file full_filename
54         end
55
56         protected
57           # Destroys the file.  Called in the after_destroy callback
58           def destroy_file
59             FileUtils.rm full_filename
60             # remove directory also if it is now empty
61             Dir.rmdir(File.dirname(full_filename)) if (Dir.entries(File.dirname(full_filename))-['.','..']).empty?
62           rescue
63             logger.info "Exception destroying  #{full_filename.inspect}: [#{$!.class.name}] #{$1.to_s}"
64             logger.warn $!.backtrace.collect { |b| " > #{b}" }.join("\n")
65           end
66
67           # Renames the given file before saving
68           def rename_file
69             return unless @old_filename && @old_filename != full_filename
70             if save_attachment? && File.exists?(@old_filename)
71               FileUtils.rm @old_filename
72             elsif File.exists?(@old_filename)
73               FileUtils.mv @old_filename, full_filename
74             end
75             @old_filename =  nil
76             true
77           end
78           
79           # Saves the file to the file system
80           def save_to_storage
81             if save_attachment?
82               # TODO: This overwrites the file if it exists, maybe have an allow_overwrite option?
83               FileUtils.mkdir_p(File.dirname(full_filename))
84               File.cp(temp_path, full_filename)
85               File.chmod(attachment_options[:chmod] || 0644, full_filename)
86             end
87             @old_filename = nil
88             true
89           end
90           
91           def current_data
92             File.file?(full_filename) ? File.read(full_filename) : nil
93           end
94       end
95     end
96   end
97 end

Benjamin Mako Hill || Want to submit a patch?