Skip to content
Browse files

comments comments comments

git-svn-id: http://svn.techno-weenie.net/projects/plugins/attachment_fu@2576 567b1171-46fb-0310-a4c9-b4bef9110e78
  • Loading branch information...
1 parent 5dc782d commit d89bfe439f34f3e12fc2b6840d69e1f95be2645f technoweenie committed Dec 23, 2006
View
2 init.rb
@@ -1,7 +1,7 @@
require 'tempfile'
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)
ext = nil
sprintf("%s%d-%d%s", basename.gsub(/\.\w+$/) { |s| ext = s; '' }, $$, n, ext)
View
96 lib/technoweenie/attachment_fu.rb
@@ -142,13 +142,15 @@ def thumbnail_class
attachment_options[:thumbnail_class]
end
+ # Copies the given file path to a new tempfile, returning the closed tempfile.
def copy_to_temp_file(file, temp_base_name)
returning Tempfile.new(temp_base_name, Technoweenie::AttachmentFu.tempfile_path) do |tmp|
tmp.close
FileUtils.cp file, tmp.path
end
end
+ # Writes the given data to a new tempfile, returning the closed tempfile.
def write_to_temp_file(data, temp_base_name)
returning Tempfile.new(temp_base_name, Technoweenie::AttachmentFu.tempfile_path) do |tmp|
tmp.write data
@@ -163,10 +165,12 @@ def image?
self.class.image?(content_type)
end
+ # Returns true/false if an attachment is thumbnailable. A thumbnailable attachment has an image content type and the parent_id attribute.
def thumbnailable?
image? && respond_to?(:parent_id)
end
+ # Returns the class used to create new thumbnails for this attachment.
def thumbnail_class
self.class.thumbnail_class
end
@@ -181,6 +185,41 @@ def thumbnail_name_for(thumbnail = nil)
"#{basename}_#{thumbnail}#{ext}"
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.
def uploaded_data() nil; end
@@ -202,59 +241,52 @@ def uploaded_data=(file_data)
self.temp_path = file_data.path
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
-
+ # Gets the latest temp path from the collection of temp paths. While working with an attachment,
+ # multiple Tempfile objects may be created for various processing purposes (resizing, for example).
+ # An array of all the tempfile objects is stored so that the Tempfile instance is held on to until
+ # it's not needed anymore. The collection is cleared after saving the attachment.
def temp_path
p = temp_paths.first
p.respond_to?(:path) ? p.path : p.to_s
end
+ # Gets an array of the currently used temp paths.
def temp_paths
@temp_paths ||= []
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)
temp_paths.unshift value
temp_path
end
+ # Gets the data from the latest temp file. This will read the file into memory.
def temp_data
save_attachment? ? File.read(temp_path) : nil
end
+ # Writes the given data to a Tempfile and adds it to the collection of temp files.
def temp_data=(data)
self.temp_path = write_to_temp_file data unless data.nil?
end
+ # Copies the given file to a randomly named Tempfile.
def copy_to_temp_file(file)
self.class.copy_to_temp_file file, random_tempfile_filename
end
+ # Writes the given file to a randomly named Tempfile.
def write_to_temp_file(data)
self.class.write_to_temp_file data, random_tempfile_filename
end
+ # Stub for creating a temp file from the attachment data. This should be defined in the backend module.
def create_temp_file() 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
-
- # Allows you to work with an RMagick representation of the attachment in a block.
+ # Allows you to work with a processed representation (RMagick, ImageScience, etc) of the attachment in a block.
#
# @attachment.with_image do |img|
# self.data = img.thumbnail(100, 100).to_blob
@@ -263,23 +295,9 @@ def image_size
def with_image(&block)
self.class.with_image(temp_path, &block)
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
+ # Generates a unique filename for a Tempfile.
def random_tempfile_filename
"#{rand Time.now.to_i}#{filename || 'attachment'}"
end
@@ -297,6 +315,7 @@ def sanitize_filename(filename)
end
end
+ # before_validation callback.
def set_size_from_temp_path
self.size = File.size(temp_path) if save_attachment?
end
@@ -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))
end
end
-
+
+ # Initializes a new thumbnail with the given suffix.
def find_or_initialize_thumbnail(file_name_suffix)
respond_to?(:parent_id) ?
thumbnail_class.find_or_initialize_by_thumbnail_and_parent_id(file_name_suffix.to_s, id) :
@@ -320,6 +340,7 @@ def process_attachment
@saved_attachment = save_attachment?
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
if @saved_attachment
if thumbnailable? && !attachment_options[:thumbnails].blank? && parent_id.nil?
@@ -333,6 +354,7 @@ def after_process_attachment
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)
if (!respond_to?(:parent_id) || parent_id.nil?) && attachment_options[:resize_to] # parent image
resize_image(img, attachment_options[:resize_to])
View
41 lib/technoweenie/attachment_fu/backends/db_file.rb
@@ -8,28 +8,31 @@ def self.included(base) #:nodoc:
base.belongs_to :db_file, :class_name => '::DbFile', :foreign_key => 'db_file_id'
end
+ # Creates a temp file with the current db data.
def create_temp_file
- write_to_temp_file db_file.data
+ write_to_temp_file current_data
end
-
- # Destroys the file. Called in the after_destroy callback
- def destroy_file
- db_file.destroy if db_file
- end
-
- # Saves the data to the DbFile model
- def save_to_storage
- if save_attachment?
- (db_file || build_db_file).data = temp_data
- db_file.save!
- self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
+
+ protected
+ # Destroys the file. Called in the after_destroy callback
+ def destroy_file
+ db_file.destroy if db_file
+ end
+
+ # Saves the data to the DbFile model
+ def save_to_storage
+ if save_attachment?
+ (db_file || build_db_file).data = temp_data
+ 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
- true
- end
-
- def current_data
- db_file.data
- end
end
end
end
View
63 lib/technoweenie/attachment_fu/backends/file_system.rb
@@ -40,41 +40,44 @@ def filename=(value)
@old_filename = full_filename unless filename.nil? || @old_filename
write_attribute :filename, sanitize_filename(value)
end
-
+
+ # Creates a temp file from the currently saved file.
def create_temp_file
copy_to_temp_file full_filename
end
-
- # Destroys the file. Called in the after_destroy callback
- def destroy_file
- FileUtils.rm full_filename rescue nil
- end
-
- 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
+
+ protected
+ # Destroys the file. Called in the after_destroy callback
+ def destroy_file
+ FileUtils.rm full_filename rescue nil
end
- @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
+
+ # Renames the given file before saving
+ 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
+
+ # 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
- @old_filename = nil
- true
- end
-
- def current_data
- File.file?(full_filename) ? File.read(full_filename) : nil
- end
end
end
end
View
53 lib/technoweenie/attachment_fu/backends/s3.rb
@@ -53,13 +53,13 @@ module Backends
# To specify S3 as the storage mechanism for a model, set the acts_as_attachment <tt>:storage</tt> option to <tt>:s3</tt>.
#
# class Photo < ActiveRecord::Base
- # acts_as_attachment :storage => :s3
+ # has_attachment :storage => :s3
# end
#
# Of course, all the usual configuration options apply:
#
- # acts_as_attachment :storage => :s3, :content_type => ['application/pdf', :image], :resize_to => 'x50'
- # acts_as_attachment :storage => :s3, :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }
+ # has_attachment :storage => :s3, :content_type => ['application/pdf', :image], :resize_to => 'x50'
+ # has_attachment :storage => :s3, :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }
module S3
class S3RequiredLibraryNotFound < StandardError; end
class S3ConfigFileNotFound < StandardError; end
@@ -109,29 +109,30 @@ def s3_url(thumbnail = nil)
def create_temp_file
write_to_temp_file current_data
end
-
- # Destroys the file. Called in the after_destroy callback
- def destroy_file
- AWS::S3::S3Object.delete filename, bucket
- end
-
- def rename_file
- return unless @old_filename && @old_filename != filename
- AWS::S3::S3Object.rename(@old_filename, filename, bucket, :access => :public_read)
- @old_filename = nil
- true
- end
-
- # Saves the file to the file system
- def save_to_storage
- AWS::S3::S3Object.store(filename, attachment_data, bucket, :content_type => content_type, :access => attachment_options[:s3_access]) if save_attachment?
- @old_filename = nil
- true
- end
-
- def current_data
- AWS::S3::S3Object.value filename, bucket
- end
+
+ protected
+ # Destroys the file. Called in the after_destroy callback
+ def destroy_file
+ AWS::S3::S3Object.delete filename, bucket
+ end
+
+ def rename_file
+ return unless @old_filename && @old_filename != filename
+ AWS::S3::S3Object.rename(@old_filename, filename, bucket, :access => :public_read)
+ @old_filename = nil
+ true
+ end
+
+ # Saves the file to S3
+ def save_to_storage
+ AWS::S3::S3Object.store(filename, attachment_data, bucket, :content_type => content_type, :access => attachment_options[:s3_access]) if save_attachment?
+ @old_filename = nil
+ true
+ end
+
+ def current_data
+ AWS::S3::S3Object.value filename, bucket
+ end
end
end
end
View
2 test/base_attachment_tests.rb
@@ -22,7 +22,7 @@ def test_reassign_attribute_data
assert attachment.save_attachment?
attachment.save!
- assert_equal 'wtf', attachment_model.find(attachment.id).current_data
+ assert_equal 'wtf', attachment_model.find(attachment.id).send(:current_data)
end
end

0 comments on commit d89bfe4

Please sign in to comment.
Something went wrong with that request. Please try again.