require 'fileutils' module PlanetArgon # :nodoc: module AssetField # :nodoc: def self.included mod # :nodoc: mod.extend ClassMethods end # Adds asset management capabilities to your model. # Usage example # # # class Page # asset_field :asset, # :directory => "#{RAILS_ROOT}/public/assets/images", # :extensions => %w( .swf .qt ), # :filename => :permalink # end # # # This defines the following attrbitues: # * [R,W] asset_tempfile # # and the following instance methods: # * Page#asset_file_on_disk Full pathname of the file on disk. # * Page#asset_exist? Does the file actually exist on disk? # * Page#write_asset_file Write the file to the path generated from the asset field's # directory option and the method referenced by the filename option. # * Page#destroy_asset_file Destroy the asset file. module ClassMethods # Configuration options are: # * :directory Directory to save this field's assets in. Defaults to # "#{RAILS_ROOT}/public/assets". # * :filename A symbol referencing the name of a method returning a string returning a # filename (minus the file's extension). It is of note that this could simply # be a reference to another attribute. # * :extensions An array of allowed file extensions. Omitting this option allows all file # extensions. def asset_field attr, options = {} uploaded_filename_method = "#{attr}_uploaded_filename" tempfile_method = "#{attr}_tempfile" write_method = "write_#{attr}_file" destroy_method = "destroy_#{attr}_file" file_on_disk_method = "#{attr}_file_on_disk" path_method = "#{attr}_path" exist_method = "#{attr}_exist?" directory_method = "#{attr}_directory" options[:directory] ||= "#{RAILS_ROOT}/public/assets" options[:filename] attr_accessor tempfile_method before_save write_method before_destroy destroy_method define_method uploaded_filename_method do self.send(tempfile_method).original_filename if self.send(tempfile_method).kind_of?(Tempfile) end define_method directory_method do @dir ||= case options[:directory] when Proc instance_eval &options[:directory] when Symbol self.send options[:directory] when String options[:directory] end end define_method file_on_disk_method do File.join self.send(directory_method), self.send(attr) end alias_method path_method, file_on_disk_method define_method exist_method do File.exist?(self.send(file_on_disk_method)) if self.send(attr) end unless options[:extensions].blank? valid_extensions = options[:extensions].map{ |e| e.gsub '.', '\.' }.join('|') validates_format_of uploaded_filename_method, :with => /.*(#{valid_extensions})$/, :allow_nil => true, :message => 'file format is disallowed' end define_method write_method do if self.send(tempfile_method) && !self.send(tempfile_method).kind_of?(String) FileUtils.mkdir_p self.send(directory_method) ext = File.extname self.send(tempfile_method).original_filename self.send destroy_method if self.send exist_method self.send "#{attr}=", self.send(options[:filename]) + ext File.open self.send(file_on_disk_method), 'w' do |f| f.write self.send(tempfile_method).read end self.send(tempfile_method).rewind raise 'Error saving file' unless self.send(exist_method) end end define_method destroy_method do File.delete self.send(file_on_disk_method) if self.send exist_method end end end end end