Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge remote branch 'upstream/master'

Conflicts:
	README.md
  • Loading branch information...
commit ce9d7eab6907103841b69dcf1346776a0c2a0350 2 parents bb5fde8 + d00c04e
@murbanski murbanski authored
View
79 README.md
@@ -25,7 +25,7 @@ that it does, on your command line, run `which convert` (one of the ImageMagick
utilities). This will give you the path where that utility is installed. For
example, it might return `/usr/local/bin/convert`.
-Then, in your environment config file, let Paperclip know to look there by adding that
+Then, in your environment config file, let Paperclip know to look there by adding that
directory to its path.
In development mode, you might add this line to `config/environments/development.rb)`:
@@ -231,6 +231,80 @@ Paperclip has an interpolation called `:hash` for obfuscating filenames of publi
[https://github.com/thoughtbot/paperclip/pull/416](https://github.com/thoughtbot/paperclip/pull/416)
+MD5 Checksum / Fingerprint
+-------
+
+A MD5 checksum of the original file assigned will be placed in the model if it
+has an attribute named fingerprint. Following the user model migration example
+above, the migration would look like the following.
+
+ class AddAvatarFingerprintColumnToUser < ActiveRecord::Migration
+ def self.up
+ add_column :users, :avatar_fingerprint, :string
+ end
+
+ def self.down
+ remove_column :users, :avatar_fingerprint
+ end
+ end
+
+Custom Attachment Processors
+-------
+
+Custom attachment processors can be implemented and their only requirement is
+to inherit from `Paperclip::Processor` (see `lib/paperclip/processor.rb`).
+For example, when `:styles` are specified for an image attachment, the
+thumbnail processor (see `lib/paperclip/thumbnail.rb`) is loaded without having
+to specify it as a `:processor` parameter to `has_attached_file`. When any
+other processor is defined it must be called out in the `:processors`
+parameter if it is to be applied to the attachment. The thumbnail processor
+uses the imagemagick `convert` command to do the work of resizing image
+thumbnails. It would be easy to create a custom processor that watermarks
+an image using imagemagick's `composite` command. Following the
+implementation pattern of the thumbnail processor would be a way to implement a
+watermark processor. All kinds of attachment processors can be created;
+a few utility examples would be compression and encryption processors.
+
+
+Dynamic Configuration
+---------------------
+
+Callable objects (labdas, Procs) can be used in a number of places for dynamic
+configuration throughout Paperclip. This strategy exists in a number of
+components of the library but is most significant in the possibilities for
+allowing custom styles and processors to be applied for specific model
+instances, rather than applying defined styles and processors across all
+instances.
+
+Dynamic Styles:
+
+Imagine a user model that had different styles based on the role of the user.
+Perhaps some users are bosses (e.g. a User model instance responds to #boss?)
+and merit a bigger avatar thumbnail than regular users. The configuration to
+determine what style parameters are to be used based on the user role might
+look as follows where a boss will receive a `300x300` thumbnail otherwise a
+`100x100` thumbnail will be created.
+
+ class User < ActiveRecord::Base
+ has_attached_file :avatar, :styles => lambda { |attachment| { :thumb => (attachment.instance.boss? ? "300x300>" : "100x100>") }
+ end
+
+Dynamic Processors:
+
+Another contrived example is a user model that is aware of which file processors
+should be applied to it (beyond the implied `thumbnail` processor invoked when
+`:styles` are defined). Perhaps we have a watermark processor available and it is
+only used on the avatars of certain models. The configuration for this might be
+where the instance is queried for which processors should be applied to it.
+Presumably some users might return `[:thumbnail, :watermark]` for its
+processors, where a defined `watermark` processor is invoked after the
+`thumbnail` processor already defined by Paperclip.
+
+ class User < ActiveRecord::Base
+ has_attached_file :avatar, :processors => lambda { |instance| instance.processors }
+ attr_accessor :watermark
+ end
+
Deploy
------
@@ -288,7 +362,6 @@ Then in `RAILS_ROOT/public/system/paperclip_attachments.yml`:
:sample:
- :thumb
-
Testing
-------
@@ -303,7 +376,7 @@ If you'd like to contribute a feature or bugfix: Thanks! To make sure your
fix/feature has a high chance of being included, please read the following
guidelines:
-1. Ask on the mailing list[http://groups.google.com/group/paperclip-plugin], or
+1. Ask on the mailing list[http://groups.google.com/group/paperclip-plugin], or
post a new GitHub Issue[http://github.com/thoughtbot/paperclip/issues].
2. Make sure there are tests! We will not accept any patch that is not tested.
It's a rare time when explicit tests aren't needed. If you have questions
View
12 lib/paperclip.rb
@@ -273,7 +273,8 @@ def has_attached_file name, options = {}
Paperclip.classes_with_attachments << self
after_save :save_attached_files
- before_destroy :destroy_attached_files
+ before_destroy :prepare_for_destroy
+ after_destroy :destroy_attached_files
define_paperclip_callbacks :post_process, :"#{name}_post_process"
@@ -409,10 +410,17 @@ def save_attached_files
def destroy_attached_files
Paperclip.log("Deleting attachments.")
each_attachment do |name, attachment|
- attachment.send(:queue_existing_for_delete)
attachment.send(:flush_deletes)
end
end
+
+ def prepare_for_destroy
+ Paperclip.log("Scheduling attachments for deletion.")
+ each_attachment do |name, attachment|
+ attachment.send(:queue_existing_for_delete)
+ end
+ end
+
end
end
View
2  lib/paperclip/attachment.rb
@@ -135,7 +135,7 @@ def assign uploaded_file
@dirty = true
- post_process(*@only_process) if @post_processing
+ post_process(*@only_process) if post_processing
# Reset the file size if the original file was reprocessed.
instance_write(:file_size, @queued_for_write[:original].size.to_i)
View
23 lib/paperclip/storage/fog.rb
@@ -42,7 +42,7 @@ def self.extended base
base.instance_eval do
@fog_directory = @options[:fog_directory]
- @fog_credentials = @options[:fog_credentials]
+ @fog_credentials = parse_credentials(@options[:fog_credentials])
@fog_host = @options[:fog_host]
@fog_public = @options.key?(:fog_public) ? @options[:fog_public] : true
@fog_file = @options[:fog_file] || {}
@@ -120,8 +120,27 @@ def public_url(style = default_style)
end
end
+ def parse_credentials(creds)
+ creds = find_credentials(creds).stringify_keys
+ env = Object.const_defined?(:Rails) ? Rails.env : nil
+ (creds[env] || creds).symbolize_keys
+ end
+
private
+ def find_credentials(creds)
+ case creds
+ when File
+ YAML::load(ERB.new(File.read(creds.path)).result)
+ when String, Pathname
+ YAML::load(ERB.new(File.read(creds)).result)
+ when Hash
+ creds
+ else
+ raise ArgumentError, "Credentials are not a path, file, or hash."
+ end
+ end
+
def connection
@connection ||= ::Fog::Storage.new(@fog_credentials)
end
@@ -129,8 +148,6 @@ def connection
def directory
@directory ||= connection.directories.new(:key => @fog_directory)
end
-
end
-
end
end
View
28 test/attachment_test.rb
@@ -1076,4 +1076,32 @@ def self.interpolate(pattern, attachment, style_name)
assert_equal "hello", attachment.url
end
end
+
+ context "An attached file" do
+ setup do
+ rebuild_model
+ @dummy = Dummy.new
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
+ @dummy.avatar = @file
+ @dummy.save!
+ @attachment = @dummy.avatar
+ @path = @attachment.path
+ end
+
+ should "not be deleted when the model fails to destroy" do
+ @dummy.stubs(:destroy).raises(Exception)
+
+ assert_raise Exception do
+ @dummy.destroy
+ end
+
+ assert File.exists?(@path)
+ end
+
+ should "be deleted when the model is destroyed" do
+ @dummy.destroy
+ assert ! File.exists?(@path)
+ end
+ end
+
end
View
8 test/fixtures/fog.yml
@@ -0,0 +1,8 @@
+development:
+ provider: AWS
+ aws_access_key_id: AWS_ID
+ aws_secret_access_key: AWS_SECRET
+test:
+ provider: AWS
+ aws_access_key_id: AWS_ID
+ aws_secret_access_key: AWS_SECRET
View
37 test/fog_test.rb
@@ -5,6 +5,39 @@
class FogTest < Test::Unit::TestCase
context "" do
+
+ context "with credentials provided in a path string" do
+ setup do
+ rebuild_model :styles => { :medium => "300x300>", :thumb => "100x100>" },
+ :storage => :fog,
+ :url => '/:attachment/:filename',
+ :fog_directory => "paperclip",
+ :fog_credentials => File.join(File.dirname(__FILE__), 'fixtures', 'fog.yml')
+ @dummy = Dummy.new
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
+ end
+
+ should "have the proper information loading credentials from a file" do
+ assert_equal @dummy.avatar.instance_variable_get("@fog_credentials")[:provider], 'AWS'
+ end
+ end
+
+ context "with credentials provided in a File object" do
+ setup do
+ rebuild_model :styles => { :medium => "300x300>", :thumb => "100x100>" },
+ :storage => :fog,
+ :url => '/:attachment/:filename',
+ :fog_directory => "paperclip",
+ :fog_credentials => File.open(File.join(File.dirname(__FILE__), 'fixtures', 'fog.yml'))
+ @dummy = Dummy.new
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
+ end
+
+ should "have the proper information loading credentials from a file" do
+ assert_equal @dummy.avatar.instance_variable_get("@fog_credentials")[:provider], 'AWS'
+ end
+ end
+
context "with default values for path and url" do
setup do
rebuild_model :styles => { :medium => "300x300>", :thumb => "100x100>" },
@@ -131,7 +164,7 @@ class FogTest < Test::Unit::TestCase
assert @dummy.avatar.url =~ /^http:\/\/img[0123]\.example\.com\/avatars\/stringio\.txt\?\d*$/
end
end
-
+
context "with fog_public set to false" do
setup do
rebuild_model(@options.merge(:fog_public => false))
@@ -139,7 +172,7 @@ class FogTest < Test::Unit::TestCase
@dummy.avatar = StringIO.new('.')
@dummy.save
end
-
+
should 'set the @fog_public instance variable to false' do
assert_equal false, @dummy.avatar.instance_variable_get('@fog_public')
end
View
8 test/upfile_test.rb
@@ -24,6 +24,14 @@ class << file
assert_equal content_type, file.content_type
end
+
+ should "return a content_type of text/plain on a real file whose content_type is determined with the file command" do
+ file = File.new(File.join(File.dirname(__FILE__), "..", "LICENSE"))
+ class << file
+ include Paperclip::Upfile
+ end
+ assert_equal 'text/plain', file.content_type
+ end
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.