paperclip 4.2.2 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.codeclimate.yml +17 -0
- data/.github/issue_template.md +3 -0
- data/.hound.yml +1055 -0
- data/.rubocop.yml +1 -0
- data/.travis.yml +17 -15
- data/Appraisals +4 -16
- data/CONTRIBUTING.md +19 -8
- data/Gemfile +5 -9
- data/LICENSE +1 -1
- data/MIGRATING-ES.md +317 -0
- data/MIGRATING.md +375 -0
- data/NEWS +184 -31
- data/README.md +371 -201
- data/RELEASING.md +17 -0
- data/Rakefile +2 -2
- data/UPGRADING +12 -9
- data/features/basic_integration.feature +10 -6
- data/features/migration.feature +0 -24
- data/features/step_definitions/attachment_steps.rb +41 -35
- data/features/step_definitions/html_steps.rb +2 -2
- data/features/step_definitions/rails_steps.rb +39 -38
- data/features/step_definitions/s3_steps.rb +2 -2
- data/features/step_definitions/web_steps.rb +1 -103
- data/features/support/env.rb +1 -0
- data/features/support/file_helpers.rb +2 -2
- data/features/support/paths.rb +1 -1
- data/features/support/rails.rb +0 -24
- data/gemfiles/4.2.gemfile +6 -8
- data/gemfiles/5.0.gemfile +17 -0
- data/lib/generators/paperclip/paperclip_generator.rb +9 -1
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +1 -1
- data/lib/paperclip/attachment.rb +51 -26
- data/lib/paperclip/attachment_registry.rb +3 -2
- data/lib/paperclip/callbacks.rb +8 -6
- data/lib/paperclip/content_type_detector.rb +27 -11
- data/lib/paperclip/errors.rb +3 -1
- data/lib/paperclip/file_command_content_type_detector.rb +6 -8
- data/lib/paperclip/filename_cleaner.rb +0 -1
- data/lib/paperclip/geometry_detector_factory.rb +3 -3
- data/lib/paperclip/geometry_parser_factory.rb +1 -1
- data/lib/paperclip/glue.rb +1 -1
- data/lib/paperclip/has_attached_file.rb +9 -2
- data/lib/paperclip/helpers.rb +15 -11
- data/lib/paperclip/interpolations/plural_cache.rb +6 -5
- data/lib/paperclip/interpolations.rb +24 -14
- data/lib/paperclip/io_adapters/abstract_adapter.rb +32 -4
- data/lib/paperclip/io_adapters/attachment_adapter.rb +17 -6
- data/lib/paperclip/io_adapters/data_uri_adapter.rb +8 -8
- data/lib/paperclip/io_adapters/empty_string_adapter.rb +5 -4
- data/lib/paperclip/io_adapters/file_adapter.rb +12 -6
- data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +8 -7
- data/lib/paperclip/io_adapters/identity_adapter.rb +12 -6
- data/lib/paperclip/io_adapters/nil_adapter.rb +8 -5
- data/lib/paperclip/io_adapters/registry.rb +6 -2
- data/lib/paperclip/io_adapters/stringio_adapter.rb +9 -6
- data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +10 -6
- data/lib/paperclip/io_adapters/uri_adapter.rb +43 -19
- data/lib/paperclip/logger.rb +1 -1
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +4 -4
- data/lib/paperclip/media_type_spoof_detector.rb +13 -9
- data/lib/paperclip/processor.rb +15 -6
- data/lib/paperclip/rails_environment.rb +25 -0
- data/lib/paperclip/schema.rb +4 -10
- data/lib/paperclip/storage/filesystem.rb +13 -2
- data/lib/paperclip/storage/fog.rb +33 -20
- data/lib/paperclip/storage/s3.rb +89 -70
- data/lib/paperclip/style.rb +0 -1
- data/lib/paperclip/thumbnail.rb +24 -12
- data/lib/paperclip/url_generator.rb +17 -13
- data/lib/paperclip/validators/attachment_size_validator.rb +1 -7
- data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +4 -0
- data/lib/paperclip/validators.rb +1 -1
- data/lib/paperclip/version.rb +3 -1
- data/lib/paperclip.rb +27 -13
- data/lib/tasks/paperclip.rake +33 -3
- data/paperclip.gemspec +18 -15
- data/spec/paperclip/attachment_definitions_spec.rb +1 -1
- data/spec/paperclip/attachment_processing_spec.rb +2 -5
- data/spec/paperclip/attachment_registry_spec.rb +84 -13
- data/spec/paperclip/attachment_spec.rb +147 -41
- data/spec/paperclip/content_type_detector_spec.rb +9 -2
- data/spec/paperclip/file_command_content_type_detector_spec.rb +15 -2
- data/spec/paperclip/filename_cleaner_spec.rb +0 -1
- data/spec/paperclip/geometry_spec.rb +1 -1
- data/spec/paperclip/glue_spec.rb +44 -0
- data/spec/paperclip/has_attached_file_spec.rb +24 -8
- data/spec/paperclip/integration_spec.rb +42 -5
- data/spec/paperclip/interpolations_spec.rb +21 -9
- data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +106 -23
- data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +6 -3
- data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +7 -1
- data/spec/paperclip/io_adapters/file_adapter_spec.rb +6 -3
- data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +51 -14
- data/spec/paperclip/io_adapters/identity_adapter_spec.rb +1 -1
- data/spec/paperclip/io_adapters/registry_spec.rb +2 -2
- data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +5 -1
- data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +5 -5
- data/spec/paperclip/io_adapters/uri_adapter_spec.rb +126 -8
- data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +10 -0
- data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +1 -1
- data/spec/paperclip/media_type_spoof_detector_spec.rb +75 -11
- data/spec/paperclip/paperclip_spec.rb +15 -40
- data/spec/paperclip/plural_cache_spec.rb +17 -16
- data/spec/paperclip/processor_spec.rb +4 -4
- data/spec/paperclip/rails_environment_spec.rb +33 -0
- data/spec/paperclip/schema_spec.rb +46 -46
- data/spec/paperclip/storage/fog_spec.rb +63 -3
- data/spec/paperclip/storage/s3_live_spec.rb +20 -14
- data/spec/paperclip/storage/s3_spec.rb +400 -215
- data/spec/paperclip/style_spec.rb +0 -1
- data/spec/paperclip/tempfile_factory_spec.rb +4 -0
- data/spec/paperclip/tempfile_spec.rb +35 -0
- data/spec/paperclip/thumbnail_spec.rb +59 -38
- data/spec/paperclip/url_generator_spec.rb +55 -45
- data/spec/paperclip/validators/attachment_size_validator_spec.rb +26 -20
- data/spec/paperclip/validators_spec.rb +5 -5
- data/spec/spec_helper.rb +7 -1
- data/spec/support/assertions.rb +12 -1
- data/spec/support/fake_model.rb +4 -0
- data/spec/support/fixtures/empty.xlsx +0 -0
- data/spec/support/matchers/have_column.rb +11 -2
- data/spec/support/mock_attachment.rb +2 -0
- data/spec/support/mock_url_generator_builder.rb +2 -2
- data/spec/support/model_reconstruction.rb +11 -3
- data/spec/support/reporting.rb +11 -0
- metadata +110 -63
- data/RUNNING_TESTS.md +0 -4
- data/cucumber/paperclip_steps.rb +0 -6
- data/gemfiles/3.2.gemfile +0 -19
- data/gemfiles/4.0.gemfile +0 -19
- data/gemfiles/4.1.gemfile +0 -19
- data/lib/paperclip/locales/de.yml +0 -18
- data/lib/paperclip/locales/es.yml +0 -18
- data/lib/paperclip/locales/ja.yml +0 -18
- data/lib/paperclip/locales/pt-BR.yml +0 -18
- data/lib/paperclip/locales/zh-CN.yml +0 -18
- data/lib/paperclip/locales/zh-HK.yml +0 -18
- data/lib/paperclip/locales/zh-TW.yml +0 -18
- data/spec/support/mock_model.rb +0 -2
- data/spec/support/rails_helpers.rb +0 -7
data/lib/paperclip/thumbnail.rb
CHANGED
@@ -3,10 +3,11 @@ module Paperclip
|
|
3
3
|
class Thumbnail < Processor
|
4
4
|
|
5
5
|
attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options,
|
6
|
-
:source_file_options, :animated, :auto_orient
|
6
|
+
:source_file_options, :animated, :auto_orient, :frame_index
|
7
7
|
|
8
8
|
# List of formats that we need to preserve animation
|
9
9
|
ANIMATED_FORMATS = %w(gif)
|
10
|
+
MULTI_FRAME_FORMATS = %w(.mkv .avi .mp4 .mov .mpg .mpeg .gif)
|
10
11
|
|
11
12
|
# Creates a Thumbnail object set to work on the +file+ given. It
|
12
13
|
# will attempt to transform the image into one defined by +target_geometry+
|
@@ -25,11 +26,11 @@ module Paperclip
|
|
25
26
|
# +whiny+ - whether to raise an error when processing fails. Defaults to true
|
26
27
|
# +format+ - the desired filename extension
|
27
28
|
# +animated+ - whether to merge all the layers in the image. Defaults to true
|
29
|
+
# +frame_index+ - the frame index of the source file to render as the thumbnail
|
28
30
|
def initialize(file, options = {}, attachment = nil)
|
29
31
|
super
|
30
32
|
|
31
33
|
geometry = options[:geometry].to_s
|
32
|
-
@file = file
|
33
34
|
@crop = geometry[-1,1] == '#'
|
34
35
|
@target_geometry = options.fetch(:string_geometry_parser, Geometry).parse(geometry)
|
35
36
|
@current_geometry = options.fetch(:file_geometry_parser, Geometry).from_file(@file)
|
@@ -42,12 +43,12 @@ module Paperclip
|
|
42
43
|
if @auto_orient && @current_geometry.respond_to?(:auto_orient)
|
43
44
|
@current_geometry.auto_orient
|
44
45
|
end
|
45
|
-
|
46
46
|
@source_file_options = @source_file_options.split(/\s+/) if @source_file_options.respond_to?(:split)
|
47
47
|
@convert_options = @convert_options.split(/\s+/) if @convert_options.respond_to?(:split)
|
48
48
|
|
49
49
|
@current_format = File.extname(@file.path)
|
50
50
|
@basename = File.basename(@file.path, @current_format)
|
51
|
+
@frame_index = multi_frame_format? ? options.fetch(:frame_index, 0) : 0
|
51
52
|
end
|
52
53
|
|
53
54
|
# Returns true if the +target_geometry+ is meant to crop.
|
@@ -64,8 +65,8 @@ module Paperclip
|
|
64
65
|
# that contains the new image.
|
65
66
|
def make
|
66
67
|
src = @file
|
67
|
-
|
68
|
-
dst.
|
68
|
+
filename = [@basename, @format ? ".#{@format}" : ""].join
|
69
|
+
dst = TempfileFactory.new.generate(filename)
|
69
70
|
|
70
71
|
begin
|
71
72
|
parameters = []
|
@@ -77,10 +78,18 @@ module Paperclip
|
|
77
78
|
|
78
79
|
parameters = parameters.flatten.compact.join(" ").strip.squeeze(" ")
|
79
80
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
frame = animated? ? "" : "[#{@frame_index}]"
|
82
|
+
convert(
|
83
|
+
parameters,
|
84
|
+
source: "#{File.expand_path(src.path)}#{frame}",
|
85
|
+
dest: File.expand_path(dst.path),
|
86
|
+
)
|
87
|
+
rescue Terrapin::ExitStatusError => e
|
88
|
+
if @whiny
|
89
|
+
message = "There was an error processing the thumbnail for #{@basename}:\n" + e.message
|
90
|
+
raise Paperclip::Error, message
|
91
|
+
end
|
92
|
+
rescue Terrapin::CommandNotFoundError => e
|
84
93
|
raise Paperclip::Errors::CommandNotFoundError.new("Could not run the `convert` command. Please install ImageMagick.")
|
85
94
|
end
|
86
95
|
|
@@ -102,7 +111,10 @@ module Paperclip
|
|
102
111
|
|
103
112
|
protected
|
104
113
|
|
105
|
-
|
114
|
+
def multi_frame_format?
|
115
|
+
MULTI_FRAME_FORMATS.include? @current_format
|
116
|
+
end
|
117
|
+
|
106
118
|
def animated?
|
107
119
|
@animated && (ANIMATED_FORMATS.include?(@format.to_s) || @format.blank?) && identified_as_animated?
|
108
120
|
end
|
@@ -113,9 +125,9 @@ module Paperclip
|
|
113
125
|
@identified_as_animated = ANIMATED_FORMATS.include? identify("-format %m :file", :file => "#{@file.path}[0]").to_s.downcase.strip
|
114
126
|
end
|
115
127
|
@identified_as_animated
|
116
|
-
rescue
|
128
|
+
rescue Terrapin::ExitStatusError => e
|
117
129
|
raise Paperclip::Error, "There was an error running `identify` for #{@basename}" if @whiny
|
118
|
-
rescue
|
130
|
+
rescue Terrapin::CommandNotFoundError => e
|
119
131
|
raise Paperclip::Errors::CommandNotFoundError.new("Could not run the `identify` command. Please install ImageMagick.")
|
120
132
|
end
|
121
133
|
end
|
@@ -1,30 +1,34 @@
|
|
1
1
|
require 'uri'
|
2
|
+
require 'active_support/core_ext/module/delegation'
|
2
3
|
|
3
4
|
module Paperclip
|
4
5
|
class UrlGenerator
|
5
|
-
def initialize(attachment
|
6
|
+
def initialize(attachment)
|
6
7
|
@attachment = attachment
|
7
|
-
@attachment_options = attachment_options
|
8
8
|
end
|
9
9
|
|
10
10
|
def for(style_name, options)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
interpolated = attachment_options[:interpolator].interpolate(
|
12
|
+
most_appropriate_url, @attachment, style_name
|
13
|
+
)
|
14
|
+
|
15
|
+
escaped = escape_url_as_needed(interpolated, options)
|
16
|
+
timestamp_as_needed(escaped, options)
|
16
17
|
end
|
17
18
|
|
18
19
|
private
|
19
20
|
|
21
|
+
attr_reader :attachment
|
22
|
+
delegate :options, to: :attachment, prefix: true
|
23
|
+
|
20
24
|
# This method is all over the place.
|
21
25
|
def default_url
|
22
|
-
if
|
23
|
-
|
24
|
-
elsif
|
25
|
-
@attachment.instance.send(
|
26
|
+
if attachment_options[:default_url].respond_to?(:call)
|
27
|
+
attachment_options[:default_url].call(@attachment)
|
28
|
+
elsif attachment_options[:default_url].is_a?(Symbol)
|
29
|
+
@attachment.instance.send(attachment_options[:default_url])
|
26
30
|
else
|
27
|
-
|
31
|
+
attachment_options[:default_url]
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
@@ -32,7 +36,7 @@ module Paperclip
|
|
32
36
|
if @attachment.original_filename.nil?
|
33
37
|
default_url
|
34
38
|
else
|
35
|
-
|
39
|
+
attachment_options[:url]
|
36
40
|
end
|
37
41
|
end
|
38
42
|
|
@@ -71,13 +71,7 @@ module Paperclip
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def human_size(size)
|
74
|
-
|
75
|
-
ActiveSupport::NumberHelper.number_to_human_size(size)
|
76
|
-
else
|
77
|
-
storage_units_format = I18n.translate(:'number.human.storage_units.format', :locale => options[:locale], :raise => true)
|
78
|
-
unit = I18n.translate(:'number.human.storage_units.units.byte', :locale => options[:locale], :count => size.to_i, :raise => true)
|
79
|
-
storage_units_format.gsub(/%n/, size.to_i.to_s).gsub(/%u/, unit).html_safe
|
80
|
-
end
|
74
|
+
ActiveSupport::NumberHelper.number_to_human_size(size)
|
81
75
|
end
|
82
76
|
|
83
77
|
def min_value_in_human_size(record)
|
@@ -8,6 +8,10 @@ module Paperclip
|
|
8
8
|
if Paperclip::MediaTypeSpoofDetector.using(adapter, value.original_filename, value.content_type).spoofed?
|
9
9
|
record.errors.add(attribute, :spoofed_media_type)
|
10
10
|
end
|
11
|
+
|
12
|
+
if adapter.tempfile
|
13
|
+
adapter.tempfile.close(true)
|
14
|
+
end
|
11
15
|
end
|
12
16
|
end
|
13
17
|
|
data/lib/paperclip/validators.rb
CHANGED
@@ -36,7 +36,7 @@ module Paperclip
|
|
36
36
|
options = attributes.extract_options!.dup
|
37
37
|
|
38
38
|
Paperclip::Validators.constants.each do |constant|
|
39
|
-
if constant.to_s =~ /\AAttachment(.+)Validator\
|
39
|
+
if constant.to_s =~ /\AAttachment(.+)Validator\z/
|
40
40
|
validator_kind = $1.underscore.to_sym
|
41
41
|
|
42
42
|
if options.has_key?(validator_kind)
|
data/lib/paperclip/version.rb
CHANGED
data/lib/paperclip.rb
CHANGED
@@ -55,11 +55,21 @@ require 'paperclip/helpers'
|
|
55
55
|
require 'paperclip/has_attached_file'
|
56
56
|
require 'paperclip/attachment_registry'
|
57
57
|
require 'paperclip/filename_cleaner'
|
58
|
-
require '
|
58
|
+
require 'paperclip/rails_environment'
|
59
|
+
|
60
|
+
begin
|
61
|
+
# Use mime/types/columnar if available, for reduced memory usage
|
62
|
+
require "mime/types/columnar"
|
63
|
+
rescue LoadError
|
64
|
+
require "mime/types"
|
65
|
+
end
|
66
|
+
|
67
|
+
require 'mimemagic'
|
68
|
+
require 'mimemagic/overlay'
|
59
69
|
require 'logger'
|
60
|
-
require '
|
70
|
+
require 'terrapin'
|
61
71
|
|
62
|
-
require 'paperclip/railtie' if defined?(Rails)
|
72
|
+
require 'paperclip/railtie' if defined?(Rails::Railtie)
|
63
73
|
|
64
74
|
# The base module that gets included in ActiveRecord::Base. See the
|
65
75
|
# documentation for Paperclip::ClassMethods for more useful information.
|
@@ -80,14 +90,15 @@ module Paperclip
|
|
80
90
|
# image's orientation. Defaults to true.
|
81
91
|
def self.options
|
82
92
|
@options ||= {
|
83
|
-
:
|
84
|
-
:
|
85
|
-
:
|
86
|
-
:
|
87
|
-
:
|
88
|
-
:
|
89
|
-
:
|
90
|
-
:
|
93
|
+
command_path: nil,
|
94
|
+
content_type_mappings: {},
|
95
|
+
log: true,
|
96
|
+
log_command: true,
|
97
|
+
read_timeout: nil,
|
98
|
+
swallow_stderr: true,
|
99
|
+
use_exif_orientation: true,
|
100
|
+
whiny: true,
|
101
|
+
is_windows: Gem.win_platform?
|
91
102
|
}
|
92
103
|
end
|
93
104
|
|
@@ -109,7 +120,7 @@ module Paperclip
|
|
109
120
|
# called on it, the attachment will *not* be deleted until +save+ is called. See the
|
110
121
|
# Paperclip::Attachment documentation for more specifics. There are a number of options
|
111
122
|
# you can set to change the behavior of a Paperclip attachment:
|
112
|
-
# * +url+: The full URL of where the attachment is
|
123
|
+
# * +url+: The full URL of where the attachment is publicly accessible. This can just
|
113
124
|
# as easily point to a directory served directly through Apache as it can to an action
|
114
125
|
# that can control permissions. You can specify the full domain and path, but usually
|
115
126
|
# just an absolute path is sufficient. The leading slash *must* be included manually for
|
@@ -118,6 +129,9 @@ module Paperclip
|
|
118
129
|
# Paperclip::Attachment#interpolate for more information on variable interpolaton.
|
119
130
|
# :url => "/:class/:attachment/:id/:style_:filename"
|
120
131
|
# :url => "http://some.other.host/stuff/:class/:id_:extension"
|
132
|
+
# Note: When using the +s3+ storage option, the +url+ option expects
|
133
|
+
# particular values. See the Paperclip::Storage::S3#url documentation for
|
134
|
+
# specifics.
|
121
135
|
# * +default_url+: The URL that will be returned if there is no attachment assigned.
|
122
136
|
# This field is interpolated just as the url is. The default value is
|
123
137
|
# "/:attachment/:style/missing.png"
|
@@ -136,7 +150,7 @@ module Paperclip
|
|
136
150
|
# user.avatar.url # => "/avatars/23/normal_me.png"
|
137
151
|
# * +keep_old_files+: Keep the existing attachment files (original + resized) from
|
138
152
|
# being automatically deleted when an attachment is cleared or updated. Defaults to +false+.
|
139
|
-
# * +preserve_files+: Keep the existing attachment files in all cases, even if the parent
|
153
|
+
# * +preserve_files+: Keep the existing attachment files in all cases, even if the parent
|
140
154
|
# record is destroyed. Defaults to +false+.
|
141
155
|
# * +whiny+: Will raise an error if Paperclip cannot post_process an uploaded file due
|
142
156
|
# to a command line error. This will override the global setting for this attachment.
|
data/lib/tasks/paperclip.rake
CHANGED
@@ -18,7 +18,7 @@ module Paperclip
|
|
18
18
|
raise "Class #{klass.name} has no attachments specified"
|
19
19
|
end
|
20
20
|
|
21
|
-
if
|
21
|
+
if name.present? && attachment_names.map(&:to_s).include?(name.to_s)
|
22
22
|
[ name ]
|
23
23
|
else
|
24
24
|
attachment_names
|
@@ -46,7 +46,7 @@ namespace :paperclip do
|
|
46
46
|
attachment = instance.send(name)
|
47
47
|
begin
|
48
48
|
attachment.reprocess!(*styles)
|
49
|
-
rescue
|
49
|
+
rescue StandardError => e
|
50
50
|
Paperclip::Task.log_error("exception while processing #{klass} ID #{instance.id}:")
|
51
51
|
Paperclip::Task.log_error(" " + e.message + "\n")
|
52
52
|
end
|
@@ -64,7 +64,8 @@ namespace :paperclip do
|
|
64
64
|
names = Paperclip::Task.obtain_attachments(klass)
|
65
65
|
names.each do |name|
|
66
66
|
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
67
|
-
|
67
|
+
attachment = instance.send(name)
|
68
|
+
if file = Paperclip.io_adapters.for(attachment, attachment.options[:adapter_options])
|
68
69
|
instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
|
69
70
|
instance.send("#{name}_content_type=", file.content_type.to_s.strip)
|
70
71
|
instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
|
@@ -90,6 +91,19 @@ namespace :paperclip do
|
|
90
91
|
end
|
91
92
|
Paperclip.save_current_attachments_styles!
|
92
93
|
end
|
94
|
+
|
95
|
+
desc "Regenerates fingerprints for a given CLASS (and optional ATTACHMENT). Useful when changing digest."
|
96
|
+
task :fingerprints => :environment do
|
97
|
+
klass = Paperclip::Task.obtain_class
|
98
|
+
names = Paperclip::Task.obtain_attachments(klass)
|
99
|
+
names.each do |name|
|
100
|
+
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
101
|
+
attachment = instance.send(name)
|
102
|
+
attachment.assign(attachment)
|
103
|
+
instance.save(:validate => false)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
93
107
|
end
|
94
108
|
|
95
109
|
desc "Cleans out invalid attachments. Useful after you've added new validations."
|
@@ -108,4 +122,20 @@ namespace :paperclip do
|
|
108
122
|
end
|
109
123
|
end
|
110
124
|
end
|
125
|
+
|
126
|
+
desc "find missing attachments. Useful to know which attachments are broken"
|
127
|
+
task :find_broken_attachments => :environment do
|
128
|
+
klass = Paperclip::Task.obtain_class
|
129
|
+
names = Paperclip::Task.obtain_attachments(klass)
|
130
|
+
names.each do |name|
|
131
|
+
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
132
|
+
attachment = instance.send(name)
|
133
|
+
if attachment.exists?
|
134
|
+
print "."
|
135
|
+
else
|
136
|
+
Paperclip::Task.log_error("#{instance.class}##{attachment.name}, #{instance.id}, #{attachment.url}")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
111
141
|
end
|
data/paperclip.gemspec
CHANGED
@@ -12,40 +12,43 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.description = "Easy upload management for ActiveRecord"
|
13
13
|
s.license = "MIT"
|
14
14
|
|
15
|
-
s.rubyforge_project = "paperclip"
|
16
|
-
|
17
15
|
s.files = `git ls-files`.split("\n")
|
18
16
|
s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
|
19
17
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
18
|
s.require_paths = ["lib"]
|
21
19
|
|
20
|
+
if File.exist?('UPGRADING')
|
21
|
+
s.post_install_message = File.read("UPGRADING")
|
22
|
+
end
|
23
|
+
|
22
24
|
s.requirements << "ImageMagick"
|
23
|
-
s.required_ruby_version = ">= 1.
|
25
|
+
s.required_ruby_version = ">= 2.1.0"
|
24
26
|
|
25
|
-
s.add_dependency('activemodel', '>=
|
26
|
-
s.add_dependency('activesupport', '>=
|
27
|
-
s.add_dependency('
|
27
|
+
s.add_dependency('activemodel', '>= 4.2.0')
|
28
|
+
s.add_dependency('activesupport', '>= 4.2.0')
|
29
|
+
s.add_dependency('terrapin', '~> 0.6.0')
|
28
30
|
s.add_dependency('mime-types')
|
31
|
+
s.add_dependency('mimemagic', '~> 0.3.0')
|
29
32
|
|
30
|
-
s.add_development_dependency('activerecord', '>=
|
33
|
+
s.add_development_dependency('activerecord', '>= 4.2.0')
|
31
34
|
s.add_development_dependency('shoulda')
|
32
|
-
s.add_development_dependency('rspec')
|
35
|
+
s.add_development_dependency('rspec', '~> 3.0')
|
33
36
|
s.add_development_dependency('appraisal')
|
34
37
|
s.add_development_dependency('mocha')
|
35
|
-
s.add_development_dependency('aws-sdk'
|
38
|
+
s.add_development_dependency('aws-sdk-s3')
|
36
39
|
s.add_development_dependency('bourne')
|
37
|
-
s.add_development_dependency('cucumber'
|
38
|
-
s.add_development_dependency('
|
40
|
+
s.add_development_dependency('cucumber-rails')
|
41
|
+
s.add_development_dependency('cucumber-expressions', '4.0.3') # TODO: investigate failures on 4.0.4
|
42
|
+
s.add_development_dependency('aruba', '~> 0.9.0')
|
39
43
|
s.add_development_dependency('nokogiri')
|
40
|
-
|
41
|
-
s.add_development_dependency('capybara', '= 2.0.3')
|
44
|
+
s.add_development_dependency('capybara')
|
42
45
|
s.add_development_dependency('bundler')
|
43
|
-
s.add_development_dependency('fog'
|
46
|
+
s.add_development_dependency('fog-aws')
|
47
|
+
s.add_development_dependency('fog-local')
|
44
48
|
s.add_development_dependency('launchy')
|
45
49
|
s.add_development_dependency('rake')
|
46
50
|
s.add_development_dependency('fakeweb')
|
47
51
|
s.add_development_dependency('railties')
|
48
|
-
s.add_development_dependency('actionmailer', '>= 3.0.0')
|
49
52
|
s.add_development_dependency('generator_spec')
|
50
53
|
s.add_development_dependency('timecop')
|
51
54
|
end
|
@@ -8,6 +8,6 @@ describe "Attachment Definitions" do
|
|
8
8
|
Dummy.do_not_validate_attachment_file_type :avatar
|
9
9
|
expected = {avatar: {path: "abc"}, other_attachment: {url: "123"}}
|
10
10
|
|
11
|
-
|
11
|
+
expect(Dummy.attachment_definitions).to eq expected
|
12
12
|
end
|
13
13
|
end
|
@@ -1,12 +1,9 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
require 'spec_helper'
|
3
2
|
|
4
3
|
describe 'Attachment Processing' do
|
5
|
-
|
6
|
-
before do
|
7
|
-
rebuild_class
|
8
|
-
end
|
4
|
+
before { rebuild_class }
|
9
5
|
|
6
|
+
context 'using validates_attachment_content_type' do
|
10
7
|
it 'processes attachments given a valid assignment' do
|
11
8
|
file = File.new(fixture_file("5k.png"))
|
12
9
|
Dummy.validates_attachment_content_type :avatar, content_type: "image/png"
|
@@ -31,8 +31,8 @@ describe 'Attachment Registry' do
|
|
31
31
|
it 'calls the block with the class, attachment name, and options' do
|
32
32
|
foo = Class.new
|
33
33
|
expected_accumulations = [
|
34
|
-
[foo, :avatar, { yo:
|
35
|
-
[foo, :greeter, { ciao:
|
34
|
+
[foo, :avatar, { yo: "greeting" }],
|
35
|
+
[foo, :greeter, { ciao: "greeting" }]
|
36
36
|
]
|
37
37
|
expected_accumulations.each do |args|
|
38
38
|
Paperclip::AttachmentRegistry.register(*args)
|
@@ -50,25 +50,92 @@ describe 'Attachment Registry' do
|
|
50
50
|
context '.definitions_for' do
|
51
51
|
it 'produces the attachment name and options' do
|
52
52
|
expected_definitions = {
|
53
|
-
avatar: { yo:
|
54
|
-
greeter: { ciao:
|
53
|
+
avatar: { yo: "greeting" },
|
54
|
+
greeter: { ciao: "greeting" }
|
55
55
|
}
|
56
56
|
foo = Class.new
|
57
|
-
Paperclip::AttachmentRegistry.register(
|
58
|
-
|
57
|
+
Paperclip::AttachmentRegistry.register(
|
58
|
+
foo,
|
59
|
+
:avatar,
|
60
|
+
yo: "greeting"
|
61
|
+
)
|
62
|
+
Paperclip::AttachmentRegistry.register(
|
63
|
+
foo,
|
64
|
+
:greeter,
|
65
|
+
ciao: "greeting"
|
66
|
+
)
|
59
67
|
|
60
68
|
definitions = Paperclip::AttachmentRegistry.definitions_for(foo)
|
61
69
|
|
62
70
|
assert_equal expected_definitions, definitions
|
63
71
|
end
|
64
72
|
|
65
|
-
it
|
66
|
-
expected_definitions = { avatar: { yo:
|
67
|
-
|
68
|
-
|
69
|
-
Paperclip::AttachmentRegistry.register(
|
73
|
+
it 'produces defintions for subclasses' do
|
74
|
+
expected_definitions = { avatar: { yo: "greeting" } }
|
75
|
+
foo = Class.new
|
76
|
+
bar = Class.new(foo)
|
77
|
+
Paperclip::AttachmentRegistry.register(
|
78
|
+
foo,
|
79
|
+
:avatar,
|
80
|
+
expected_definitions[:avatar]
|
81
|
+
)
|
82
|
+
|
83
|
+
definitions = Paperclip::AttachmentRegistry.definitions_for(bar)
|
84
|
+
|
85
|
+
assert_equal expected_definitions, definitions
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'produces defintions for subclasses but deep merging them' do
|
89
|
+
foo_definitions = { avatar: { yo: "greeting" } }
|
90
|
+
bar_definitions = { avatar: { ciao: "greeting" } }
|
91
|
+
expected_definitions = {
|
92
|
+
avatar: {
|
93
|
+
yo: "greeting",
|
94
|
+
ciao: "greeting"
|
95
|
+
}
|
96
|
+
}
|
97
|
+
foo = Class.new
|
98
|
+
bar = Class.new(foo)
|
99
|
+
Paperclip::AttachmentRegistry.register(
|
100
|
+
foo,
|
101
|
+
:avatar,
|
102
|
+
foo_definitions[:avatar]
|
103
|
+
)
|
104
|
+
Paperclip::AttachmentRegistry.register(
|
105
|
+
bar,
|
106
|
+
:avatar,
|
107
|
+
bar_definitions[:avatar]
|
108
|
+
)
|
109
|
+
|
110
|
+
definitions = Paperclip::AttachmentRegistry.definitions_for(bar)
|
70
111
|
|
71
|
-
|
112
|
+
assert_equal expected_definitions, definitions
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'allows subclasses to override attachment defitions' do
|
116
|
+
foo_definitions = { avatar: { yo: "greeting" } }
|
117
|
+
bar_definitions = { avatar: { yo: "hello" } }
|
118
|
+
|
119
|
+
expected_definitions = {
|
120
|
+
avatar: {
|
121
|
+
yo: "hello"
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
foo = Class.new
|
126
|
+
bar = Class.new(foo)
|
127
|
+
Paperclip::AttachmentRegistry.register(
|
128
|
+
foo,
|
129
|
+
:avatar,
|
130
|
+
foo_definitions[:avatar]
|
131
|
+
)
|
132
|
+
Paperclip::AttachmentRegistry.register(
|
133
|
+
bar,
|
134
|
+
:avatar,
|
135
|
+
bar_definitions[:avatar]
|
136
|
+
)
|
137
|
+
|
138
|
+
definitions = Paperclip::AttachmentRegistry.definitions_for(bar)
|
72
139
|
|
73
140
|
assert_equal expected_definitions, definitions
|
74
141
|
end
|
@@ -77,7 +144,11 @@ describe 'Attachment Registry' do
|
|
77
144
|
context '.clear' do
|
78
145
|
it 'removes all of the existing attachment definitions' do
|
79
146
|
foo = Class.new
|
80
|
-
Paperclip::AttachmentRegistry.register(
|
147
|
+
Paperclip::AttachmentRegistry.register(
|
148
|
+
foo,
|
149
|
+
:greeter,
|
150
|
+
ciao: "greeting"
|
151
|
+
)
|
81
152
|
|
82
153
|
Paperclip::AttachmentRegistry.clear
|
83
154
|
|