Commit 13318e61 by jyurek

Initial version

git-svn-id: https://svn.thoughtbot.com/plugins/paperclip/trunk@160 7bbfaf0e-4d1d-0410-9690-a8bb5f8ef2aa
parents
Paperclip
=========
Paperclip is a lightweight attachment manager for ActiveRecord. It saves and manages your attachments be they images or Word Doc with one line of code. You can automatically thumbnail images as they're uploaded, and you don't have to worry about installing any ruby-specific libraries. You don't have to worry about compiling headaches with RMagick, concurrency issues and race conditions with MiniMagick, or unsupported image types with ImageScience. All you need is a working Image- or GraphicsMagick installation.
Paperclip uses the filesystem to save your files. You specify a root that the files will be saved to, and, if you're attaching images, any other formats they need to be converted to, and they'll all be saved to the right place when your object saves. They can even validate beforehand, so you'll know if your user tries to upload an HTML doc as an image.
Usage
-----
In your model:
class Photo < ActiveRecord::Base
has_attached_file :image, :thumbnails => { :medium => "300x300>", :thumb => "100x100>" }
end
In your view:
<% form_for :photo, @photo, :url => photo_path do |form| %>
<%= form.file_field :image %>
<% end %>
In your controller:
def create
@photo = Photo.create( params[:photo] )
end
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
desc 'Default: run unit tests.'
task :default => :test
desc 'Test the paperclip plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
desc 'Generate documentation for the paperclip plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'Paperclip'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end
require File.join(File.dirname(__FILE__), "lib", "paperclip")
ActiveRecord::Base.extend( Thoughtbot::Paperclip::ClassMethods )
\ No newline at end of file
# Install hook code here
module Thoughtbot
module Paperclip
DEFAULT_OPTIONS = {
:path_prefix => ":rails_root/public/",
:url_prefix => "/",
:path => ":class/:style/:id",
:attachment_type => :image,
:thumbnails => {}
}
module ClassMethods
def has_attached_file *file_attribute_names
options = file_attribute_names.last.is_a?(Hash) ? file_attribute_names.pop : {}
options = DEFAULT_OPTIONS.merge(options)
include InstanceMethods
attachments ||= {}
file_attribute_names.each do |attr|
attachments[attr] = (attachments[attr] || {:name => attr}).merge(options)
define_method "#{attr}=" do |uploaded_file|
attachments[attr].merge!({
:dirty => true,
:files => {:original => uploaded_file},
:content_type => uploaded_file.content_type,
:filename => sanitize_filename(uploaded_file.original_filename)
})
write_attribute(:"#{attr}_file_name", attachments[attr][:filename])
write_attribute(:"#{attr}_content_type", attachments[attr][:content_type])
if attachments[attr][:attachment_type] == :image
attachments[attr][:thumbnails].each do |style, geometry|
attachments[attr][:files][style] = make_thumbnail(attachments[attr][:files][:original], geometry)
end
end
uploaded_file
end
define_method "#{attr}_attachment" do
attachments[attr]
end
define_method "#{attr}_filename" do |*args|
style = args.shift || :original # This prevents arity warnings
path_for attachments[attr], style
end
define_method "#{attr}_url" do |*args|
style = args.shift || :original # This prevents arity warnings
url_for attachments[attr], style
end
define_method "#{attr}_valid?" do
attachments[attr][:thumbnails].all? do |style, geometry|
attachments[attr][:dirty] ?
!attachments[attr][:files][style].blank? :
File.file?( path_for(attachments[attr], style))
end
end
define_method "#{attr}_after_save" do
if attachments[attr].keys.any?
write_attachment attachments[attr]
attachments[attr][:dirty] = false
attachments[attr][:files] = nil
end
end
private :"#{attr}_after_save"
after_save :"#{attr}_after_save"
define_method "#{attr}_before_destroy" do
if attachments[attr].keys.any?
delete_attachment attachments[attr]
end
end
private :"#{attr}_before_destroy"
before_destroy :"#{attr}_before_destroy"
end
end
end
module InstanceMethods
def path_for attachment, style
prefix = File.join(attachment[:path_prefix], attachment[:path])
prefix.gsub!(/:rails_root/, RAILS_ROOT)
prefix.gsub!(/:id/, self.id.to_s) if self.id
prefix.gsub!(/:class/, self.class.to_s.underscore)
prefix.gsub!(/:style/, style.to_s)
File.join( prefix.split("/"), read_attribute("#{attachment[:name]}_file_name") )
end
def url_for attachment, style
prefix = File.join(attachment[:url_prefix], attachment[:path])
prefix.gsub!(/:rails_root/, RAILS_ROOT)
prefix.gsub!(/:id/, self.id.to_s) if self.id
prefix.gsub!(/:class/, self.class.to_s.underscore)
prefix.gsub!(/:style/, style.to_s)
File.join( prefix.split("/"), read_attribute("#{attachment[:name]}_file_name") )
end
def ensure_directories_for attachment
attachment[:files].keys.each do |style|
dirname = File.dirname(path_for(attachment, style))
FileUtils.mkdir_p dirname
end
end
def write_attachment attachment
ensure_directories_for attachment
attachment[:files].each do |style, atch|
File.open( path_for(attachment, style), "w" ) do |file|
atch.rewind
file.write(atch.read)
end
end
end
def delete_attachment attachment
(attachment[:thumbnails].keys + [:original]).each do |style|
FileUtils.rm path_for(attachment, style)
end
end
def make_thumbnail orig_io, geometry
thumb = IO.popen("convert - -scale '#{geometry}' - > /dev/stdout", "w+") do |io|
orig_io.rewind
io.write(orig_io.read)
io.close_write
io.read
end
raise "Convert returned with result code #{$?.exitstatus}." unless $?.success?
StringIO.new(thumb)
end
def sanitize_filename filename
File.basename(filename).gsub(/[^\w\.\_]/,'_')
end
protected :sanitize_filename
end
module Upfile
def content_type
type = self.path.match(/\.(\w+)$/)[1]
case type
when "jpg", "png", "gif" then "image/#{type}"
when "txt", "csv", "xml", "html", "htm" then "text/#{type}"
else "application/#{type}"
end
end
def original_filename
self.path
end
end
end
end
File.send :include, Thoughtbot::Paperclip::Upfile
# desc "Explaining what the task does"
# task :paperclip do
# # Task goes here
# end
\ No newline at end of file
test:
adapter: sqlite3
dbfile: paperclip.db
#database: ":memory:"
\ No newline at end of file
This diff is collapsed. Click to expand it.
begin
ActiveRecord::Base.connection.create_table :foos do |table|
table.column :image_file_name, :string
table.column :image_content_type, :string
end
ActiveRecord::Base.connection.create_table :bars do |table|
table.column :document_file_name, :string
table.column :document_content_type, :string
end
rescue Exception
end
class Foo < ActiveRecord::Base
has_attached_file :image, :attachment_type => :image,
:thumbnails => { :thumb => "100x100>", :medium => "300x300>" },
:path_prefix => "."
end
class Bar < ActiveRecord::Base
has_attached_file :document, :attachment_type => :document,
:path_prefix => "."
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 PaperclipImagesTest < Test::Unit::TestCase
def setup
assert @foo = Foo.new
assert @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', 'test_image.jpg'))
assert @foo.image = @file
end
def test_should_validate_before_save
assert @foo.image_valid?
assert @foo.valid?
end
def test_should_save_the_file_and_its_thumbnails
assert @foo.save
assert File.exists?( @foo.image_filename(:original) )
assert File.exists?( @foo.image_filename(:medium) )
assert File.exists?( @foo.image_filename(:thumb) )
assert File.size?( @foo.image_filename(:original) )
assert File.size?( @foo.image_filename(:medium) )
assert File.size?( @foo.image_filename(:thumb) )
`identify '#{@foo.image_filename(:original)}'`; assert $?.exitstatus == 0
`identify '#{@foo.image_filename(:medium)}'`; assert $?.exitstatus == 0
`identify '#{@foo.image_filename(:thumb)}'`; assert $?.exitstatus == 0
end
def test_should_validate_to_make_sure_the_thumbnails_exist
assert @foo.save
assert @foo.image_valid?
assert @foo.valid?
end
def test_should_delete_all_thumbnails_on_destroy
assert @foo.save
assert @foo.destroy
assert !File.exists?( @foo.image_filename(:original) )
assert !File.exists?( @foo.image_filename(:medium) )
assert !File.exists?( @foo.image_filename(:thumb) )
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 PaperclipTest < Test::Unit::TestCase
def setup
assert @bar = Bar.new
assert @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', 'test_document.doc'))
assert @bar.document = @file
end
def test_should_validate_before_save
assert @bar.document_valid?
assert @bar.valid?
end
def test_should_save_the_created_file_to_the_final_asset_directory
assert @bar.save
assert File.exists?( @bar.document_filename )
end
def test_should_validate
assert @bar.save
assert @bar.document_valid?
assert @bar.valid?
end
def test_should_delete_files_on_destroy
assert @bar.save
assert File.exists?( @bar.document_filename )
assert @bar.destroy
assert !File.exists?( @bar.document_filename )
end
end
\ No newline at end of file
require 'rubygems'
require 'test/unit'
require 'active_record'
require 'active_record/fixtures'
require 'fileutils'
require 'pp'
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
ActiveRecord::Base.establish_connection(config[ENV['RAILS_ENV'] || 'test'])
Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
$LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
RAILS_ROOT = "test" unless Object.const_defined? "RAILS_ROOT"
class Test::Unit::TestCase #:nodoc:
def create_fixtures(*table_names)
if block_given?
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
else
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
end
end
def self.load_all_fixtures
all_fixtures = Dir.glob("#{File.dirname(__FILE__)}/fixtures/*.yml").collect do |f|
puts "Loading fixture '#{f}'"
File.basename(f).gsub(/\.yml$/, "").to_sym
end
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, all_fixtures)
end
# Turn off transactional fixtures if you're working with MyISAM tables in MySQL
self.use_transactional_fixtures = true
# Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)
self.use_instantiated_fixtures = false
# Add more helper methods to be used by all tests here...
end
\ No newline at end of file
# Uninstall hook code here
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