Skip to content

Commit

Permalink
comments comments comments
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.techno-weenie.net/projects/plugins/attachment_fu@2576 567b1171-46fb-0310-a4c9-b4bef9110e78
  • Loading branch information
technoweenie committed Dec 23, 2006
1 parent 5dc782d commit d89bfe4
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 114 deletions.
2 changes: 1 addition & 1 deletion init.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'tempfile' require 'tempfile'


Tempfile.class_eval do Tempfile.class_eval do
# overwrite so tempfiles keep the basename extension # overwrite so tempfiles use the extension of the basename. important for rmagick and image science
def make_tmpname(basename, n) def make_tmpname(basename, n)
ext = nil ext = nil
sprintf("%s%d-%d%s", basename.gsub(/\.\w+$/) { |s| ext = s; '' }, $$, n, ext) sprintf("%s%d-%d%s", basename.gsub(/\.\w+$/) { |s| ext = s; '' }, $$, n, ext)
Expand Down
96 changes: 59 additions & 37 deletions lib/technoweenie/attachment_fu.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -142,13 +142,15 @@ def thumbnail_class
attachment_options[:thumbnail_class] attachment_options[:thumbnail_class]
end end


# Copies the given file path to a new tempfile, returning the closed tempfile.
def copy_to_temp_file(file, temp_base_name) def copy_to_temp_file(file, temp_base_name)
returning Tempfile.new(temp_base_name, Technoweenie::AttachmentFu.tempfile_path) do |tmp| returning Tempfile.new(temp_base_name, Technoweenie::AttachmentFu.tempfile_path) do |tmp|
tmp.close tmp.close
FileUtils.cp file, tmp.path FileUtils.cp file, tmp.path
end end
end end


# Writes the given data to a new tempfile, returning the closed tempfile.
def write_to_temp_file(data, temp_base_name) def write_to_temp_file(data, temp_base_name)
returning Tempfile.new(temp_base_name, Technoweenie::AttachmentFu.tempfile_path) do |tmp| returning Tempfile.new(temp_base_name, Technoweenie::AttachmentFu.tempfile_path) do |tmp|
tmp.write data tmp.write data
Expand All @@ -163,10 +165,12 @@ def image?
self.class.image?(content_type) self.class.image?(content_type)
end end


# Returns true/false if an attachment is thumbnailable. A thumbnailable attachment has an image content type and the parent_id attribute.
def thumbnailable? def thumbnailable?
image? && respond_to?(:parent_id) image? && respond_to?(:parent_id)
end end


# Returns the class used to create new thumbnails for this attachment.
def thumbnail_class def thumbnail_class
self.class.thumbnail_class self.class.thumbnail_class
end end
Expand All @@ -181,6 +185,41 @@ def thumbnail_name_for(thumbnail = nil)
"#{basename}_#{thumbnail}#{ext}" "#{basename}_#{thumbnail}#{ext}"
end end


# Creates or updates the thumbnail for the current attachment.
def create_or_update_thumbnail(temp_file, file_name_suffix, *size)
thumbnailable? || raise(ThumbnailError.new("Can't create a thumbnail if the content type is not an image or there is no parent_id column"))
returning find_or_initialize_thumbnail(file_name_suffix) do |thumb|
thumb.attributes = {
:content_type => content_type,
:filename => thumbnail_name_for(file_name_suffix),
:temp_path => temp_file,
:thumbnail_resize_options => size
}
callback_with_args :before_thumbnail_saved, thumb
thumb.save!
end
end

# Sets the content type.
def content_type=(new_type)
write_attribute :content_type, new_type.to_s.strip
end

# Sanitizes a filename.
def filename=(new_name)
write_attribute :filename, sanitize_filename(new_name)
end

# Returns the width/height in a suitable format for the image_tag helper: (100x100)
def image_size
[width.to_s, height.to_s] * 'x'
end

# Returns true if the attachment data will be written to the storage system on the next save
def save_attachment?
File.file?(temp_path.to_s)
end

# nil placeholder in case this field is used in a form. # nil placeholder in case this field is used in a form.
def uploaded_data() nil; end def uploaded_data() nil; end


Expand All @@ -202,59 +241,52 @@ def uploaded_data=(file_data)
self.temp_path = file_data.path self.temp_path = file_data.path
end end


# returns true if the attachment data will be written to the storage system on the next save # Gets the latest temp path from the collection of temp paths. While working with an attachment,
def save_attachment? # multiple Tempfile objects may be created for various processing purposes (resizing, for example).
File.file?(temp_path.to_s) # An array of all the tempfile objects is stored so that the Tempfile instance is held on to until
end # it's not needed anymore. The collection is cleared after saving the attachment.

def temp_path def temp_path
p = temp_paths.first p = temp_paths.first
p.respond_to?(:path) ? p.path : p.to_s p.respond_to?(:path) ? p.path : p.to_s
end end


# Gets an array of the currently used temp paths.
def temp_paths def temp_paths
@temp_paths ||= [] @temp_paths ||= []
end end


# Adds a new temp_path to the array. This should take a string or a Tempfile. This class makes no
# attempt to remove the files, so Tempfiles should be used. Tempfiles remove themselves when they go out of scope.
# You can also use string paths for temporary files, such as those used for uploaded files in a web server.
def temp_path=(value) def temp_path=(value)
temp_paths.unshift value temp_paths.unshift value
temp_path temp_path
end end


# Gets the data from the latest temp file. This will read the file into memory.
def temp_data def temp_data
save_attachment? ? File.read(temp_path) : nil save_attachment? ? File.read(temp_path) : nil
end end


# Writes the given data to a Tempfile and adds it to the collection of temp files.
def temp_data=(data) def temp_data=(data)
self.temp_path = write_to_temp_file data unless data.nil? self.temp_path = write_to_temp_file data unless data.nil?
end end


# Copies the given file to a randomly named Tempfile.
def copy_to_temp_file(file) def copy_to_temp_file(file)
self.class.copy_to_temp_file file, random_tempfile_filename self.class.copy_to_temp_file file, random_tempfile_filename
end end


# Writes the given file to a randomly named Tempfile.
def write_to_temp_file(data) def write_to_temp_file(data)
self.class.write_to_temp_file data, random_tempfile_filename self.class.write_to_temp_file data, random_tempfile_filename
end end


# Stub for creating a temp file from the attachment data. This should be defined in the backend module.
def create_temp_file() end def create_temp_file() end


# Sets the content type. # Allows you to work with a processed representation (RMagick, ImageScience, etc) of the attachment in a block.
def content_type=(new_type)
write_attribute :content_type, new_type.to_s.strip
end

# sanitizes a filename.
def filename=(new_name)
write_attribute :filename, sanitize_filename(new_name)
end

# Returns the width/height in a suitable format for the image_tag helper: (100x100)
def image_size
[width.to_s, height.to_s] * 'x'
end

# Allows you to work with an RMagick representation of the attachment in a block.
# #
# @attachment.with_image do |img| # @attachment.with_image do |img|
# self.data = img.thumbnail(100, 100).to_blob # self.data = img.thumbnail(100, 100).to_blob
Expand All @@ -263,23 +295,9 @@ def image_size
def with_image(&block) def with_image(&block)
self.class.with_image(temp_path, &block) self.class.with_image(temp_path, &block)
end end

# Creates or updates the thumbnail for the current attachment.
def create_or_update_thumbnail(temp_file, file_name_suffix, *size)
thumbnailable? || raise(ThumbnailError.new("Can't create a thumbnail if the content type is not an image or there is no parent_id column"))
returning find_or_initialize_thumbnail(file_name_suffix) do |thumb|
thumb.attributes = {
:content_type => content_type,
:filename => thumbnail_name_for(file_name_suffix),
:temp_path => temp_file,
:thumbnail_resize_options => size
}
callback_with_args :before_thumbnail_saved, thumb
thumb.save!
end
end


protected protected
# Generates a unique filename for a Tempfile.
def random_tempfile_filename def random_tempfile_filename
"#{rand Time.now.to_i}#{filename || 'attachment'}" "#{rand Time.now.to_i}#{filename || 'attachment'}"
end end
Expand All @@ -297,6 +315,7 @@ def sanitize_filename(filename)
end end
end end


# before_validation callback.
def set_size_from_temp_path def set_size_from_temp_path
self.size = File.size(temp_path) if save_attachment? self.size = File.size(temp_path) if save_attachment?
end end
Expand All @@ -308,7 +327,8 @@ def attachment_attributes_valid?
errors.add attr_name, ActiveRecord::Errors.default_error_messages[:inclusion] unless enum.nil? || enum.include?(send(attr_name)) errors.add attr_name, ActiveRecord::Errors.default_error_messages[:inclusion] unless enum.nil? || enum.include?(send(attr_name))
end end
end end


# Initializes a new thumbnail with the given suffix.
def find_or_initialize_thumbnail(file_name_suffix) def find_or_initialize_thumbnail(file_name_suffix)
respond_to?(:parent_id) ? respond_to?(:parent_id) ?
thumbnail_class.find_or_initialize_by_thumbnail_and_parent_id(file_name_suffix.to_s, id) : thumbnail_class.find_or_initialize_by_thumbnail_and_parent_id(file_name_suffix.to_s, id) :
Expand All @@ -320,6 +340,7 @@ def process_attachment
@saved_attachment = save_attachment? @saved_attachment = save_attachment?
end end


# Cleans up after processing. Thumbnails are created, the attachment is stored to the backend, and the temp_paths are cleared.
def after_process_attachment def after_process_attachment
if @saved_attachment if @saved_attachment
if thumbnailable? && !attachment_options[:thumbnails].blank? && parent_id.nil? if thumbnailable? && !attachment_options[:thumbnails].blank? && parent_id.nil?
Expand All @@ -333,6 +354,7 @@ def after_process_attachment
end end
end end


# Resizes the given processed img object with either the attachment resize options or the thumbnail resize options.
def resize_image_or_thumbnail!(img) def resize_image_or_thumbnail!(img)
if (!respond_to?(:parent_id) || parent_id.nil?) && attachment_options[:resize_to] # parent image if (!respond_to?(:parent_id) || parent_id.nil?) && attachment_options[:resize_to] # parent image
resize_image(img, attachment_options[:resize_to]) resize_image(img, attachment_options[:resize_to])
Expand Down
41 changes: 22 additions & 19 deletions lib/technoweenie/attachment_fu/backends/db_file.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -8,28 +8,31 @@ def self.included(base) #:nodoc:
base.belongs_to :db_file, :class_name => '::DbFile', :foreign_key => 'db_file_id' base.belongs_to :db_file, :class_name => '::DbFile', :foreign_key => 'db_file_id'
end end


# Creates a temp file with the current db data.
def create_temp_file def create_temp_file
write_to_temp_file db_file.data write_to_temp_file current_data
end end


# Destroys the file. Called in the after_destroy callback protected
def destroy_file # Destroys the file. Called in the after_destroy callback
db_file.destroy if db_file def destroy_file
end db_file.destroy if db_file

end
# Saves the data to the DbFile model
def save_to_storage # Saves the data to the DbFile model
if save_attachment? def save_to_storage
(db_file || build_db_file).data = temp_data if save_attachment?
db_file.save! (db_file || build_db_file).data = temp_data
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id] db_file.save!
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
end
true
end

# Gets the current data from the database
def current_data
db_file.data
end end
true
end

def current_data
db_file.data
end
end end
end end
end end
Expand Down
63 changes: 33 additions & 30 deletions lib/technoweenie/attachment_fu/backends/file_system.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -40,41 +40,44 @@ def filename=(value)
@old_filename = full_filename unless filename.nil? || @old_filename @old_filename = full_filename unless filename.nil? || @old_filename
write_attribute :filename, sanitize_filename(value) write_attribute :filename, sanitize_filename(value)
end end


# Creates a temp file from the currently saved file.
def create_temp_file def create_temp_file
copy_to_temp_file full_filename copy_to_temp_file full_filename
end end


# Destroys the file. Called in the after_destroy callback protected
def destroy_file # Destroys the file. Called in the after_destroy callback
FileUtils.rm full_filename rescue nil def destroy_file
end FileUtils.rm full_filename rescue nil

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 end
@old_filename = nil
true # Renames the given file before saving
end def rename_file

return unless @old_filename && @old_filename != full_filename
# Saves the file to the file system if save_attachment? && File.exists?(@old_filename)
def save_to_storage FileUtils.rm @old_filename
if save_attachment? elsif File.exists?(@old_filename)
# TODO: This overwrites the file if it exists, maybe have an allow_overwrite option? FileUtils.mv @old_filename, full_filename
FileUtils.mkdir_p(File.dirname(full_filename)) end
FileUtils.mv temp_path, full_filename @old_filename = nil
true
end

# Saves the file to the file system
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.mv temp_path, full_filename
end
@old_filename = nil
true
end

def current_data
File.file?(full_filename) ? File.read(full_filename) : nil
end end
@old_filename = nil
true
end

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

0 comments on commit d89bfe4

Please sign in to comment.