Permalink
Browse files

New hotness. Holy crap.

git-svn-id: https://svn.thoughtbot.com/plugins/paperclip/trunk@229 7bbfaf0e-4d1d-0410-9690-a8bb5f8ef2aa
  • Loading branch information...
1 parent 72c4e73 commit 8911e40efb804c39675e13f29b43e1dc396a8e4e jyurek committed Oct 25, 2007
View
2 generators/paperclip/templates/paperclip_migration.rb
@@ -3,13 +3,15 @@ def self.up
<% attachments.each do |attachment| -%>
add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_name, :string
add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_content_type, :string
+ add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_size, :integer
<% end -%>
end
def self.down
<% attachments.each do |attachment| -%>
remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_name
remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_content_type
+ remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_size
<% end -%>
end
end
View
270 lib/paperclip.rb
@@ -10,8 +10,272 @@
#
# See the +has_attached_file+ documentation for more details.
-require 'paperclip/paperclip'
-require 'paperclip/storage'
+require 'paperclip/upfile'
+require 'paperclip/attachment'
+require 'paperclip/attachment_definition'
require 'paperclip/storage/filesystem'
-require 'paperclip/storage/s3'
+module Thoughtbot #:nodoc:
+ # Paperclip defines an attachment as any file, though it makes special considerations
+ # for image files. You can declare that a model has an attached file with the
+ # +has_attached_file+ method:
+ #
+ # class User < ActiveRecord::Base
+ # has_attached_file :avatar, :thumbnails => { :thumb => "100x100" }
+ # end
+ #
+ # See the +has_attached_file+ documentation for more details.
+ module Paperclip
+
+ class << self
+ # Provides configurability to Paperclip. There are a number of options available, such as:
+ # * whiny_deletes: Will raise an error if Paperclip is unable to delete an attachment. Defaults to false.
+ # * whiny_thumbnails: Will raise an error if Paperclip cannot process thumbnails of an uploaded image. Defaults to true.
+ # * image_magick_path: Defines the path at which to find the +convert+ and +identify+ programs if they are
+ # not visible to Rails the system's search path. Defaults to nil, which uses the first executable found
+ # in the search path.
+ def options
+ @options ||= {
+ :whiny_deletes => false,
+ :whiny_thumbnails => true,
+ :image_magick_path => nil
+ }
+ end
+
+ def path_for_command command #:nodoc:
+ path = [options[:image_magick_path], command].compact
+ File.join(*path)
+ end
+ end
+
+ class PaperclipError < StandardError #:nodoc:
+ attr_accessor :attachment
+ def initialize attachment
+ @attachment = attachment
+ end
+ end
+
+ module ClassMethods
+ # == Methods
+ # +has_attached_file+ attaches a file (or files) with a given name to a model. It creates seven instance
+ # methods using the attachment name (where "attachment" in the following is the name
+ # passed in to +has_attached_file+):
+ # * attachment: Returns the name of the file that was attached, with no path information.
+ # * attachment?: Alias for _attachment_ for clarity in determining if the attachment exists.
+ # * attachment=(file): Sets the attachment to the file and creates the thumbnails (if necessary).
+ # +file+ can be anything normally accepted as an upload (+StringIO+ or +Tempfile+) or a +File+
+ # if it has had the +Upfile+ module included.
+ # Note this does not save the attachments.
+ # user.avatar = File.new("~/pictures/me.png")
+ # user.avatar = params[:user][:avatar] # When :avatar is a file_field
+ # * attachment_file_name(style): The name of the file, including path information. Pass in the
+ # name of a thumbnail to get the path to that thumbnail.
+ # user.avatar_file_name(:thumb) # => "public/users/44/thumb/me.png"
+ # user.avatar_file_name # => "public/users/44/original/me.png"
+ # * attachment_url(style): The public URL of the attachment, suitable for passing to +image_tag+
+ # or +link_to+. Pass in the name of a thumbnail to get the url to that thumbnail.
+ # user.avatar_url(:thumb) # => "http://assethost.com/users/44/thumb/me.png"
+ # user.avatar_url # => "http://assethost.com/users/44/original/me.png"
+ # * attachment_valid?: If unsaved, returns true if all thumbnails have data (that is,
+ # they were successfully made). If saved, returns true if all expected files exist and are
+ # of nonzero size.
+ # * destroy_attachment(complain = false): Deletes the attachment and all thumbnails. Sets the +attachment_file_name+
+ # column and +attachment_content_type+ column to +nil+. Set +complain+ to true to override
+ # the +whiny_deletes+ option.
+ #
+ # == Options
+ # There are a number of options you can set to change the behavior of Paperclip.
+ # * +path_prefix+: The location of the repository of attachments on disk. See Interpolation below
+ # for more control over where the files are located.
+ # :path_prefix => ":rails_root/public"
+ # :path_prefix => "/var/app/repository"
+ # * +url_prefix+: The root URL of where the attachment is publically accessible. See Interpolation below
+ # for more control over where the files are located.
+ # :url_prefix => "/"
+ # :url_prefix => "/user_files"
+ # :url_prefix => "http://some.other.host/stuff"
+ # * +path+: Where the files are stored underneath the +path_prefix+ directory and underneath the +url_prefix+ URL.
+ # See Interpolation below for more control over where the files are located.
+ # :path => ":class/:style/:id/:name" # => "users/original/13/picture.gif"
+ # * +attachment_type+: If this is set to :image (which it is, by default), Paperclip will attempt to make thumbnails.
+ # * +thumbnails+: A hash of thumbnail styles and their geometries. You can find more about geometry strings
+ # at the ImageMagick website (http://www.imagemagick.org/script/command-line-options.php#resize). Paperclip
+ # also adds the "#" option, which will resize the image to fit maximally inside the dimensions and then crop
+ # the rest off (weighted at the center).
+ # * +delete_on_destroy+: When records are deleted, the attachment that goes with it is also deleted. Set
+ # this to +false+ to prevent the file from being deleted.
+ # * +default_style+: The thumbnail style that will be used by default for +attachment_file_name+ and +attachment_url+
+ # Defaults to +original+.
+ # has_attached_file :avatar, :thumbnails => { :normal => "100x100#" },
+ # :default_style => :normal
+ # user.avatar_url # => "/avatars/23/normal_me.png"
+ # * +missing_url+: The URL that will be returned if there is no attachment assigned. It should be an absolute
+ # URL, not relative to the +url_prefix+. This field is interpolated.
+ # has_attached_file :avatar, :missing_url => "/images/default_:style_avatar.png"
+ # User.new.avatar_url(:small) # => "/images/default_small_avatar.png"
+ #
+ # == Interpolation
+ # The +path_prefix+, +url_prefix+, and +path+ options can have dynamic interpolation done so that the
+ # locations of the files can vary depending on a variety of factors. Each variable looks like a Ruby symbol
+ # and is searched for with +gsub+, so a variety of effects can be achieved. The list of possible variables
+ # follows:
+ # * +rails_root+: The value of the +RAILS_ROOT+ constant for your app. Typically used when putting your
+ # attachments into the public directory. Probably not useful in the +path+ definition.
+ # * +class+: The underscored, pluralized version of the class in which the attachment is defined.
+ # * +attachment+: The pluralized name of the attachment as given to +has_attached_file+
+ # * +style+: The name of the thumbnail style for the current thumbnail. If no style is given, "original" is used.
+ # * +id+: The record's id.
+ # * +name+: The file's name, as stored in the attachment_file_name column.
+ #
+ # When interpolating, you are not confined to making any one of these into its own directory. This is
+ # perfectly valid:
+ # :path => ":attachment/:style/:id-:name" # => "avatars/thumb/44-me.png"
+ #
+ # == Model Requirements
+ # For any given attachment _foo_, the model the attachment is in needs to have both a +foo_file_name+
+ # and +foo_content_type+ column, as a type of +string+. The +foo_file_name+ column contains only the name
+ # of the file and none of the path information. However, the +foo_file_name+ column accessor is overwritten
+ # by the one (defined above) which returns the full path to whichever style thumbnail is passed in.
+ # In a pinch, you can either use +read_attribute+ or the plain +foo+ accessor, which returns the database's
+ # +foo_file_name+ column.
+ #
+ # == Event Triggers
+ # When an attachment is set by using he setter (+model.attachment=+), the thumbnails are created and held in
+ # memory. They are not saved until the +after_save+ trigger fires, at which point the attachment and all
+ # thumbnails are written to disk.
+ #
+ # Attached files are destroyed when the associated record is destroyed in a +before_destroy+ trigger. Set
+ # the +delete_on_destroy+ option to +false+ to prevent this behavior. Also note that using the ActiveRecord's
+ # +delete+ method instead of the +destroy+ method will prevent the +before_destroy+ trigger from firing.
+ def has_attached_file *attachment_names
+ options = attachment_names.last.is_a?(Hash) ? attachment_names.pop : {}
+ @attachment_definitions ||= {}
+
+ class << self
+ attr_accessor :attachment_definitions
+ end
+ include InstanceMethods
+
+ validates_each(*attachment_names) do |record, attr, value|
+ value.errors.each{|e| record.errors.add(attr, e) unless record.errors.on(attr) && record.errors.on(attr).include?(e) }
+ end
+
+ attachment_names.each do |name|
+ whine_about_columns_for name
+ @attachment_definitions[name] = Thoughtbot::Paperclip::AttachmentDefinition.new(name, options)
+
+ define_method "#{name}=" do |uploaded_file|
+ attachment_for(name).assign uploaded_file
+ end
+
+ define_method name do
+ attachment_for(name)
+ end
+
+ define_method "#{name}?" do
+ attachment_for(name).original_filename
+ end
+
+ define_method "#{name}_valid?" do
+ attachment_for(name).valid?
+ end
+
+ define_method "#{name}_file_name" do |*args|
+ attachment_for(name).file_name(args.first)
+ end
+
+ define_method "#{name}_url" do |*args|
+ attachment_for(name).url(args.first)
+ end
+
+ define_method "destroy_#{name}" do |*args|
+ attachment_for(name).queue_destroy(args.first)
+ end
+
+ define_method "#{name}_after_save" do
+ attachment_for(name).save
+ end
+ private :"#{name}_after_save"
+ after_save :"#{name}_after_save"
+
+ define_method "#{name}_before_destroy" do
+ attachment_for(name).destroy
+ end
+ private :"#{name}_before_destroy"
+ before_destroy :"#{name}_before_destroy"
+ end
+ end
+
+ module InstanceMethods #:nodoc:
+ unless method_defined? :after_initialize
+ def after_initialize
+ # We need this, because Rails won't even try this method unless it is specifically defined.
+ end
+ end
+
+ def after_initialize_with_paperclip
+ @attachments = {}
+ self.class.attachment_definitions.keys.each do |name|
+ @attachments[name] = Thoughtbot::Paperclip::Attachment.new(name, self)
+ end
+ end
+ alias_method_chain :after_initialize, :paperclip
+
+ def attachment_for name
+ @attachments[name]
+ end
+ end
+
+ def attachment_names
+ @attachment_definitions.keys
+ end
+
+ def validates_attached_file *attachment_names
+ attachment_names.each do |name|
+ @attachment_definitions[name].validate :existence
+ end
+ end
+
+ def whine_about_columns_for name #:nodoc:
+ [ "#{name}_file_name", "#{name}_content_type", "#{name}_size" ].each do |column|
+ unless column_names.include?(column)
+ raise PaperclipError, "Class #{self.name} does not have all of the necessary columns to have an attachment named #{name}. " +
+ "(#{name}_file_name, #{name}_content_type, and #{name}_size)"
+ end
+ end
+ end
+
+ end
+
+ # == Storage Subsystems
+ # While Paperclip focuses primarily on using the filesystem for data storage, it is possible to allow
+ # other storage mediums. A module inside the Storage module can be used as the storage provider for
+ # attachments when has_attached_file is given the +storage+ option. The value of the option should be
+ # the name of the module, symbol-ized (e.g. :filesystem, :s3). You can look at the Filesystem and S3
+ # modules for examples of how it typically works.
+ #
+ # If you want to implement a storage system, you are required to implement the following methods:
+ # * file_name(style = nil): Takes a style (i.e. thumbnail name) and should return the canonical name
+ # for referencing that file or thumbnail. You may define this how you wish. For example, in
+ # Filesystem, it is the location of the file under the path_prefix. In S3, it returns the path portion
+ # of the Amazon URL minus the bucket name.
+ # * url(style = nil): Takes a style and should return the URL at which the attachment should be accessed.
+ # * write_attachment: Write all the files and thumbnails in this attachment to the storage medium. Should
+ # return true or false depending on success.
+ # * delete_attachment: Delete the files and thumbnails from the storage medium. Should return true or false
+ # depending on success.
+ #
+ # When writing files, the @files variable will hold a hash of style names and their data. If @files is nil,
+ # then no new data has been assigned to the attachment and you should not perform any work.
+ #
+ # You will also have access to @definition, which is the AttachmentDefintion object for the attachment. The
+ # methods in your module will be mixed into an Attachment instance, so you have full access to the
+ # Attachment itself.
+ #
+ # == Validations
+ # Storage systems provide their own validations, since the manner of checking the status of them is usually
+ # specific to the means of storage. To provide a validation, define a method starting with "validate_" in
+ # your module. You are responsible for adding errors to the +errors+ array if validation fails.
+ module Storage; end
+ end
+end
View
104 lib/paperclip/storage/filesystem.rb
@@ -1,78 +1,80 @@
module Thoughtbot
module Paperclip
-
- module ClassMethods
- def has_attached_file_with_filesystem *attachment_names
- has_attached_file_without_filesystem *attachment_names
- end
- alias_method_chain :has_attached_file, :filesystem
- end
-
- class Storage #:nodoc:
- class Filesystem < Storage #:nodoc:
- 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
+ module Storage
+ # == Filesystem
+ # Typically, Paperclip stores your files in the filesystem, so that Apache (or whatever your
+ # main asset server is) can easily access your files without Rails having to be called all
+ # the time.
+ module Filesystem
- interpolate attachment, "#{attachment[:url_prefix]}/#{attachment[:path]}", style
+ def file_name style = nil
+ style ||= @definition.default_style
+ pattern = if original_filename && instance.id
+ File.join(@definition.path_prefix, @definition.path)
+ else
+ @definition.missing_file_name
+ end
+ interpolate( style, pattern )
end
- def ensure_directories_for attachment
- attachment[:files].each do |style, file|
- dirname = File.dirname(path_for(attachment, style))
- FileUtils.mkdir_p dirname
+ def url style = nil
+ style ||= @definition.default_style
+ pattern = if original_filename && instance.id
+ [@definition.url_prefix, @definition.url || @definition.path].compact.join("/")
+ else
+ @definition.missing_url
end
+ interpolate( style, pattern )
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|
+ def write_attachment
+ return if @files.blank?
+ ensure_directories
+ @files.each do |style, data|
+ data.rewind
+ data = data.read
+ File.open( file_name(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)
+ def delete_attachment complain = false
+ @definition.styles.keys.each do |style|
+ file_path = file_name(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
+ raise PaperclipError.new(self), "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
+
+ def validate_existence *constraints
+ @definition.styles.keys.each do |style|
+ if @dirty
+ errors << "requires a valid #{style} file." unless @files && @files[style]
else
- false
+ errors << "requires a valid #{style} file." unless File.exists?( file_name(style) )
end
end
end
+
+ def validate_size *constraints
+ errors << "file too large. Must be under #{constraints.last} bytes." if original_file_size > constraints.last
+ errors << "file too small. Must be over #{constraints.first} bytes." if original_file_size <= constraints.first
+ end
+
+ private
+
+ def ensure_directories
+ @files.each do |style, file|
+ dirname = File.dirname( file_name(style) )
+ FileUtils.mkdir_p dirname
+ end
+ end
+
end
end
end
View
143 lib/paperclip/storage/s3.rb
@@ -1,9 +1,9 @@
module Thoughtbot
module Paperclip
- module ClassMethods
+ module ClassMethods #:nodoc:
def has_attached_file_with_s3 *attachment_names
- attachments, options = has_attached_file_without_s3 *attachment_names
+ has_attached_file_without_s3 *attachment_names
access_key = secret_key = ""
if file_name = s3_credentials_file
@@ -16,7 +16,7 @@ def has_attached_file_with_s3 *attachment_names
secret_key = Thoughtbot::Paperclip.options[:s3_secret_access_key]
end
- if options[:storage].to_s.downcase == "s3"
+ if @definition.storage_module == Thoughtbot::Paperclip::Storage::S3
require 'aws/s3'
AWS::S3::Base.establish_connection!(
:access_key_id => access_key,
@@ -35,66 +35,113 @@ def s3_credentials_file
nil
end
end
+
+ class AttachmentDefinition
+ def s3_access
+ @options[:s3_access_privilege]
+ end
+ end
+
+ module Storage
+ # == Amazon S3 Storage
+ # Paperclip can store your files in Amazon's S3 Web Service. You can keep your keys in an s3.yml
+ # file inside the +config+ directory, similarly to your database.yml.
+ #
+ # access_key_id: 12345
+ # secret_access_key: 212434...4656456
+ #
+ # You can also environment-namespace the entries like you would in your database.yml:
+ #
+ # development:
+ # access_key_id: 12345
+ # secret_access_key: 212434...4656456
+ # production:
+ # access_key_id: abcde
+ # secret_access_key: gbkjhg...wgbrtjh
+ #
+ # The location of this file is configurable. You don't even have to use it if you don't want. Both
+ # the file's location or the keys themselves may be located in the Thoughtbot::Paperclip.options
+ # hash. The S3-related options in this hash are all prefixed with "s3".
+ #
+ # Thoughtbot::Paperclip.options = {
+ # :s3_persistent => true,
+ # :s3_credentials_file => "/home/me/.private/s3.yml"
+ # }
+ #
+ # This configuration is best placed in your +environment.rb+ or env-specific file.
+ # The complete list of options is as follows:
+ # * s3_access_key_id: The Amazon S3 ID you were given to access your account.
+ # * s3_secret_access_key: The secret key supplied by Amazon. This should be kept far away from prying
+ # eyes, which is why it's suggested that you keep these keys in a separate file that
+ # only you and the database can read.
+ # * s3_credentials_file: The path to the file where your credentials are kept in YAML format, as
+ # described above.
+ # * s3_persistent: Maintains an HTTP connection to the Amazon service if possible.
+ module S3
+ def file_name style = nil
+ style ||= @definition.default_style
+ pattern = if original_filename && instance.id
+ @definition.url
+ else
+ @definition.missing_url
+ end
+ interpolate( style, pattern )
+ end
+
+ def url style = nil
+ "http://s3.amazonaws.com/#{bucket}/#{file_name(style)}"
+ end
- class Storage #:nodoc:
- class S3 < Storage #:nodoc:
- def path_for attachment, style = nil
- style ||= attachment[:default_style]
- file = attachment[:instance]["#{attachment[:name]}_file_name"]
- return nil unless file && attachment[:instance].id
+ def write_attachment
+ return if @files.blank?
+ bucket = ensure_bucket
+ @files.each do |style, data|
+ data.rewind
+ AWS::S3::S3Object.store( file_name(style), data, bucket, :access => @definition.s3_access || :public_read )
+ end
+ end
- interpolate attachment, attachment[:path], style
+ def delete_attachment complain = false
+ (attachment[:thumbnails].keys + [:original]).each do |style|
+ begin
+ AWS::S3::S3Object.delete( file_name(style), bucket )
+ rescue AWS::S3::ResponseError => error
+ raise
+ end
+ end
+ end
+
+ def validate_existence *constraints
+ @definition.styles.keys.each do |style|
+ if @dirty
+ errors << "requires a valid #{style} file." unless @files && @files[style]
+ else
+ errors << "requires a valid #{style} file." unless AWS::S3::S3Object.exists?( file_name(style), bucket )
+ end
+ end
end
- def url_for attachment, style = nil
- "http://s3.amazonaws.com/#{bucket_for(attachment)}/#{path_for(attachment, style)}"
+ def validate_size *constraints
+ errors << "file too large. Must be under #{constraints.last} bytes." if original_file_size > constraints.last
+ errors << "file too small. Must be over #{constraints.first} bytes." if original_file_size <= constraints.first
end
-
- def bucket_for attachment
- bucket_name = interpolate attachment, attachment[:url_prefix], nil
+
+ private
+
+ def bucket
+ interpolate(nil, @definition.url_prefix)
end
- def ensure_bucket_for attachment, style = nil
+ def ensure_bucket
begin
- bucket_name = bucket_for attachment
+ bucket_name = bucket
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
View
6 test/models.rb
@@ -2,22 +2,28 @@
ActiveRecord::Base.connection.create_table :foos, :force => true do |table|
table.column :image_file_name, :string
table.column :image_content_type, :string
+ table.column :image_size, :integer
end
ActiveRecord::Base.connection.create_table :bars, :force => true do |table|
table.column :document_file_name, :string
table.column :document_content_type, :string
+ table.column :document_size, :integer
end
ActiveRecord::Base.connection.create_table :non_standards, :force => true do |table|
table.column :resume_file_name, :string
table.column :resume_content_type, :string
+ table.column :resume_size, :integer
table.column :avatar_file_name, :string
table.column :avatar_content_type, :string
+ table.column :avatar_size, :integer
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 :resume_size, :integer
table.column :avatar_file_name, :string
table.column :avatar_content_type, :string
+ table.column :avatar_size, :integer
end
ActiveRecord::Base.connection.create_table :negatives, :force => true do |table|
table.column :this_is_the_wrong_name_file_name, :string
View
8 test/paperclip_images_test.rb
@@ -22,7 +22,7 @@ def test_should_validate_before_save
end
def test_should_save_the_file_and_its_thumbnails
- assert @foo.save
+ assert @foo.save, @foo.errors.full_messages.inspect
assert File.exists?( @foo.image_file_name(:original) ), @foo.image_file_name(:original)
assert File.exists?( @foo.image_file_name(:medium) ), @foo.image_file_name(:medium)
assert File.exists?( @foo.image_file_name(:thumb) ), @foo.image_file_name(:thumb)
@@ -43,7 +43,7 @@ def test_should_validate_to_make_sure_the_thumbnails_exist
def test_should_ensure_that_file_are_accessible_after_reload
assert @foo.save
assert @foo.image_valid?
- assert @foo.valid?
+ assert @foo.valid?, @foo.errors.full_messages.inspect
@foo2 = Foo.find @foo.id
assert @foo.image_valid?
@@ -72,7 +72,7 @@ def test_should_ensure_file_names_and_urls_are_empty_if_no_file_set
end
assert @foo.destroy_image
- assert @foo.save
+ assert @foo.save, @foo.errors.full_messages.inspect
mappings.each do |style, file, url|
assert_not_equal file, @foo.image_file_name(style)
assert_equal "", @foo.image_file_name(style)
@@ -128,8 +128,8 @@ def test_should_put_errors_on_object_if_convert_does_not_exist
Thoughtbot::Paperclip.options[:image_magick_path] = "/does/not/exist"
assert_nothing_raised{ @foo.image = @file }
- assert !@foo.save
assert !@foo.valid?
+ assert !@foo.save, @foo.errors.full_messages.inspect
assert @foo.errors.length > 0
assert @foo.errors.on(:image)
[@foo.errors.on(:image)].flatten.each do |err|
View
12 test/paperclip_test.rb
@@ -15,8 +15,8 @@ def test_should_supply_all_attachment_names
end
def test_should_validate_before_save
- assert @bar.document_valid?
- assert @bar.valid?
+ assert @bar.document_valid?, @bar.errors.full_messages.inspect
+ assert @bar.valid?, @bar.errors.full_messages.inspect
end
def test_should_save_the_created_file_to_the_final_asset_directory
@@ -25,9 +25,9 @@ def test_should_save_the_created_file_to_the_final_asset_directory
end
def test_should_validate
- assert @bar.save
- assert @bar.document_valid?
- assert @bar.valid?
+ assert @bar.save, @bar.errors.full_messages.inspect
+ assert @bar.document_valid?, @bar.errors.full_messages.inspect
+ assert @bar.valid?, @bar.errors.full_messages.inspect
end
def test_should_default_to_original_for_path_and_url
@@ -47,7 +47,7 @@ def test_should_delete_files_on_destroy
def test_should_put_on_errors_if_no_file_exists
assert @bar.save
@bar.document = nil
- assert !@bar.document_valid?
+ assert !@bar.document_valid?, @bar.errors.full_messages.inspect
assert !@bar.save
assert @bar.errors.length > 0
assert @bar.errors.on(:document)

0 comments on commit 8911e40

Please sign in to comment.