Commit 66b47339 by jyurek

A little reorg, plus added S3 support.

git-svn-id: https://svn.thoughtbot.com/plugins/paperclip/trunk@222 7bbfaf0e-4d1d-0410-9690-a8bb5f8ef2aa
parent 16b60a52
module Thoughtbot
module Paperclip
class Storage
def interpolate attachment, source, style
style ||= attachment[:default_style]
file_name = attachment[:instance]["#{attachment[:name]}_file_name"]
returning source.dup do |s|
s.gsub!(/:rails_root/, RAILS_ROOT)
s.gsub!(/:id/, attachment[:instance].id.to_s) if attachment[:instance].id
s.gsub!(/:class/, attachment[:instance].class.to_s.underscore.pluralize)
s.gsub!(/:style/, style.to_s )
s.gsub!(/:attachment/, attachment[:name].to_s.pluralize)
if file_name
file_bits = file_name.split(".")
s.gsub!(/:name/, file_name)
s.gsub!(/:base/, [file_bits[0], *file_bits[1..-2]].join("."))
s.gsub!(/:ext/, file_bits.last )
end
end
end
def make_thumbnails attachment
attachment[:files] ||= {}
attachment[:files][:original] ||= File.new( path_for(attachment, :original) )
attachment[:thumbnails].each do |style, geometry|
begin
attachment[:files][style] = make_thumbnail(attachment, attachment[:files][:original], geometry)
rescue PaperclipError => e
attachment[:errors] << "thumbnail '#{style}' could not be created."
end
end
end
def make_thumbnail attachment, orig_io, geometry
operator = geometry[-1,1]
begin
geometry, crop_geometry = geometry_for_crop(geometry, orig_io) if operator == '#'
command = "#{path_for_command "convert"} - -scale '#{geometry}' #{operator == '#' ? "-crop '#{crop_geometry}'" : ""} - 2>/dev/null"
thumb = IO.popen(command, "w+") do |io|
orig_io.rewind
io.write(orig_io.read)
io.close_write
StringIO.new(io.read)
end
rescue Errno::EPIPE => e
raise PaperclipError.new(attachment), "Could not create thumbnail. Is ImageMagick or GraphicsMagick installed and available?"
rescue SystemCallError => e
raise PaperclipError.new(attachment), "Could not create thumbnail."
end
if ::Thoughtbot::Paperclip.options[:whiny_thumbnails] && !$?.success?
raise PaperclipError.new(attachment), "Convert returned with result code #{$?.exitstatus}: #{thumb.read}"
end
thumb
end
def geometry_for_crop geometry, orig_io
IO.popen("#{path_for_command "identify"} - 2>/dev/null", "w+") do |io|
orig_io.rewind
io.write(orig_io.read)
io.close_write
if match = io.read.split[2].match(/(\d+)x(\d+)/)
src = match[1,2].map(&:to_f)
srch = src[0] > src[1]
dst = geometry.match(/(\d+)x(\d+)/)[1,2].map(&:to_f)
dsth = dst[0] > dst[1]
ar = src[0] / src[1]
scale_geometry, scale = if dst[0] == dst[1]
if srch
[ "x#{dst[1]}", src[1] / dst[1] ]
else
[ "#{dst[0]}x", src[0] / dst[0] ]
end
elsif dsth
[ "#{dst[0]}x", src[0] / dst[0] ]
else
[ "x#{dst[1]}", src[1] / dst[1] ]
end
crop_geometry = if dsth
"%dx%d+%d+%d" % [ dst[0], dst[1], 0, (src[1] / scale - dst[1]) / 2 ]
else
"%dx%d+%d+%d" % [ dst[0], dst[1], (src[0] / scale - dst[0]) / 2, 0 ]
end
[ scale_geometry, crop_geometry ]
end
end
end
def path_for_command command
File.join([::Thoughtbot::Paperclip.options[:image_magick_path], command].compact)
end
def to_s
self.class.name
end
end
end
end
\ No newline at end of file
module Thoughtbot
module Paperclip
module ClassMethods
def has_attached_file_with_fs *attachment_names
has_attached_file_without_fs *attachment_names
end
alias_method_chain :has_attached_file, :fs
end
class Storage
class Filesystem < Storage
def path_for attachment, style = nil
style ||= attachment[:default_style]
file = attachment[:instance]["#{attachment[:name]}_file_name"]
return nil unless file && attachment[:instance].id
prefix = interpolate attachment, "#{attachment[:path_prefix]}/#{attachment[:path]}", style
File.join( prefix.split("/") )
end
def url_for attachment, style = nil
style ||= attachment[:default_style]
file = attachment[:instance]["#{attachment[:name]}_file_name"]
return nil unless file && attachment[:instance].id
interpolate attachment, "#{attachment[:url_prefix]}/#{attachment[:path]}", style
end
def ensure_directories_for attachment
attachment[:files].each do |style, file|
dirname = File.dirname(path_for(attachment, style))
FileUtils.mkdir_p dirname
end
end
def write_attachment attachment
return if attachment[:files].blank?
ensure_directories_for attachment
attachment[:files].each do |style, atch|
atch.rewind
data = atch.read
File.open( path_for(attachment, style), "w" ) do |file|
file.rewind
file.write(data)
end
end
attachment[:files] = nil
attachment[:dirty] = false
end
def delete_attachment attachment, complain = false
(attachment[:thumbnails].keys + [:original]).each do |style|
file_path = path_for(attachment, style)
begin
FileUtils.rm file_path if file_path
rescue SystemCallError => e
raise PaperclipError.new(attachment), "Could not delete thumbnail." if ::Thoughtbot::Paperclip.options[:whiny_deletes] || complain
end
end
end
def attachment_valid? attachment
attachment[:thumbnails].merge(:original => nil).all? do |style, geometry|
if attachment[:instance]["#{attachment[:name]}_file_name"]
if attachment[:dirty]
!attachment[:files][style].blank? && attachment[:errors].empty?
else
File.file?( path_for(attachment, style) )
end
else
false
end
end
end
end
end
end
end
\ No newline at end of file
module Thoughtbot
module Paperclip
module ClassMethods
def has_attached_file_with_s3 *attachment_names
attachments, options = has_attached_file_without_s3 *attachment_names
access_key = secret_key = ""
if file_name = s3_credentials_file
creds = YAML.load_file(file_name)
creds = creds[RAILS_ENV] || creds if Object.const_defined?("RAILS_ENV")
access_key = creds['access_key_id']
secret_key = creds['secret_access_key']
else
access_key = Thoughtbot::Paperclip.options[:s3_access_key_id]
secret_key = Thoughtbot::Paperclip.options[:s3_secret_access_key]
end
if options[:storage].to_s.downcase == "s3"
require 'aws/s3'
AWS::S3::Base.establish_connection!(
:access_key_id => access_key,
:secret_access_key => secret_key,
:persistent => Thoughtbot::Paperclip.options[:s3_persistent] || true
)
end
end
alias_method_chain :has_attached_file, :s3
private
def s3_credentials_file
[ Thoughtbot::Paperclip.options[:s3_credentials_file], File.join(RAILS_ROOT, "config", "s3.yml") ].compact.each do |f|
return f if File.exists?(f)
end
nil
end
end
class Storage
class S3 < Storage
def path_for attachment, style = nil
style ||= attachment[:default_style]
file = attachment[:instance]["#{attachment[:name]}_file_name"]
return nil unless file && attachment[:instance].id
interpolate attachment, attachment[:path], style
end
def url_for attachment, style = nil
"http://s3.amazonaws.com/#{bucket_for(attachment)}/#{path_for(attachment, style)}"
end
def bucket_for attachment
bucket_name = interpolate attachment, attachment[:url_prefix], nil
end
def ensure_bucket_for attachment, style = nil
begin
bucket_name = bucket_for attachment
AWS::S3::Bucket.create(bucket_name)
bucket_name
rescue AWS::S3::S3Exception => e
raise Thoughtbot::Paperclip::PaperclipError.new(attachment), "You are not allowed access to the bucket '#{bucket_name}'."
end
end
def write_attachment attachment
return if attachment[:files].blank?
bucket = ensure_bucket_for attachment
attachment[:files].each do |style, atch|
atch.rewind
AWS::S3::S3Object.store( path_for(attachment, style), atch, bucket, :access => attachment[:access] || :public_read )
end
attachment[:files] = nil
attachment[:dirty] = false
end
def delete_attachment attachment, complain = false
(attachment[:thumbnails].keys + [:original]).each do |style|
file_path = path_for(attachment, style)
AWS::S3::S3Object.delete( file_path, bucket_for(attachment) )
end
end
def attachment_valid? attachment
attachment[:thumbnails].merge(:original => nil).all? do |style, geometry|
if attachment[:instance]["#{attachment[:name]}_file_name"]
if attachment[:dirty]
!attachment[:files][style].blank? && attachment[:errors].empty?
else
AWS::S3::S3Object.exists?( path_for(attachment, style), bucket_for(attachment) )
end
else
false
end
end
end
end
end
end
end
\ No newline at end of file
...@@ -13,6 +13,12 @@ begin ...@@ -13,6 +13,12 @@ begin
table.column :avatar_file_name, :string table.column :avatar_file_name, :string
table.column :avatar_content_type, :string table.column :avatar_content_type, :string
end end
ActiveRecord::Base.connection.create_table :ess_threes, :force => true do |table|
table.column :resume_file_name, :string
table.column :resume_content_type, :string
table.column :avatar_file_name, :string
table.column :avatar_content_type, :string
end
ActiveRecord::Base.connection.create_table :negatives, :force => true do |table| ActiveRecord::Base.connection.create_table :negatives, :force => true do |table|
table.column :this_is_the_wrong_name_file_name, :string table.column :this_is_the_wrong_name_file_name, :string
end end
...@@ -47,5 +53,23 @@ class NonStandard < ActiveRecord::Base ...@@ -47,5 +53,23 @@ class NonStandard < ActiveRecord::Base
:missing_url => "/:class/:style/:attachment/404.png" :missing_url => "/:class/:style/:attachment/404.png"
end end
# class EssThree < ActiveRecord::Base
# has_attached_file :resume, :attachment_type => :document,
# :path_prefix => "paperclip/test",
# :path => ":attachment_:id_:name",
# :missing_url => "/:class/:style/:attachment/404.txt",
# :storage => :S3
# has_attached_file :avatar, :attachment_type => :image,
# :thumbnails => { :cropped => "200x10#",
# :bigger => "1000x1000",
# :smaller => "200x200>",
# :square => "150x150#" },
# :path_prefix => "paperclip/test/images",
# :path => ":class/:attachment/:id/:style_:name",
# :default_style => :square,
# :missing_url => "/:class/:style/:attachment/404.png",
# :storage => :S3
# end
class Negative < ActiveRecord::Base class Negative < ActiveRecord::Base
end end
\ No newline at end of file
require 'test/unit'
require File.dirname(__FILE__) + "/test_helper.rb"
require File.dirname(__FILE__) + "/../init.rb"
require File.join(File.dirname(__FILE__), "models.rb")
class PaperclipS3Test < Test::Unit::TestCase
def setup
end
def test_truth
assert true
end
end
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment