kt-paperclip 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.codeclimate.yml +17 -0
- data/.github/issue_template.md +3 -0
- data/.gitignore +19 -0
- data/.hound.yml +1050 -0
- data/.rubocop.yml +1 -0
- data/.travis.yml +47 -0
- data/Appraisals +24 -0
- data/CONTRIBUTING.md +86 -0
- data/Gemfile +18 -0
- data/LICENSE +24 -0
- data/NEWS +515 -0
- data/README.md +1053 -0
- data/RELEASING.md +17 -0
- data/Rakefile +52 -0
- data/UPGRADING +17 -0
- data/features/basic_integration.feature +85 -0
- data/features/migration.feature +29 -0
- data/features/rake_tasks.feature +62 -0
- data/features/step_definitions/attachment_steps.rb +110 -0
- data/features/step_definitions/html_steps.rb +15 -0
- data/features/step_definitions/rails_steps.rb +257 -0
- data/features/step_definitions/s3_steps.rb +14 -0
- data/features/step_definitions/web_steps.rb +106 -0
- data/features/support/env.rb +12 -0
- data/features/support/fakeweb.rb +11 -0
- data/features/support/file_helpers.rb +34 -0
- data/features/support/fixtures/boot_config.txt +15 -0
- data/features/support/fixtures/gemfile.txt +5 -0
- data/features/support/fixtures/preinitializer.txt +20 -0
- data/features/support/paths.rb +28 -0
- data/features/support/rails.rb +39 -0
- data/features/support/selectors.rb +19 -0
- data/gemfiles/4.2.gemfile +20 -0
- data/gemfiles/5.0.gemfile +20 -0
- data/gemfiles/5.1.gemfile +20 -0
- data/gemfiles/5.2.gemfile +20 -0
- data/gemfiles/6.0.gemfile +20 -0
- data/lib/generators/paperclip/USAGE +8 -0
- data/lib/generators/paperclip/paperclip_generator.rb +36 -0
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +15 -0
- data/lib/paperclip.rb +215 -0
- data/lib/paperclip/attachment.rb +617 -0
- data/lib/paperclip/attachment_registry.rb +60 -0
- data/lib/paperclip/callbacks.rb +42 -0
- data/lib/paperclip/content_type_detector.rb +80 -0
- data/lib/paperclip/errors.rb +34 -0
- data/lib/paperclip/file_command_content_type_detector.rb +28 -0
- data/lib/paperclip/filename_cleaner.rb +15 -0
- data/lib/paperclip/geometry.rb +157 -0
- data/lib/paperclip/geometry_detector_factory.rb +45 -0
- data/lib/paperclip/geometry_parser_factory.rb +31 -0
- data/lib/paperclip/glue.rb +17 -0
- data/lib/paperclip/has_attached_file.rb +116 -0
- data/lib/paperclip/helpers.rb +60 -0
- data/lib/paperclip/interpolations.rb +201 -0
- data/lib/paperclip/interpolations/plural_cache.rb +18 -0
- data/lib/paperclip/io_adapters/abstract_adapter.rb +75 -0
- data/lib/paperclip/io_adapters/attachment_adapter.rb +47 -0
- data/lib/paperclip/io_adapters/data_uri_adapter.rb +22 -0
- data/lib/paperclip/io_adapters/empty_string_adapter.rb +19 -0
- data/lib/paperclip/io_adapters/file_adapter.rb +26 -0
- data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +16 -0
- data/lib/paperclip/io_adapters/identity_adapter.rb +17 -0
- data/lib/paperclip/io_adapters/nil_adapter.rb +37 -0
- data/lib/paperclip/io_adapters/registry.rb +36 -0
- data/lib/paperclip/io_adapters/stringio_adapter.rb +36 -0
- data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +44 -0
- data/lib/paperclip/io_adapters/uri_adapter.rb +68 -0
- data/lib/paperclip/locales/en.yml +18 -0
- data/lib/paperclip/logger.rb +21 -0
- data/lib/paperclip/matchers.rb +64 -0
- data/lib/paperclip/matchers/have_attached_file_matcher.rb +54 -0
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +101 -0
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +59 -0
- data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +97 -0
- data/lib/paperclip/media_type_spoof_detector.rb +90 -0
- data/lib/paperclip/missing_attachment_styles.rb +84 -0
- data/lib/paperclip/processor.rb +56 -0
- data/lib/paperclip/processor_helpers.rb +52 -0
- data/lib/paperclip/rails_environment.rb +21 -0
- data/lib/paperclip/railtie.rb +31 -0
- data/lib/paperclip/schema.rb +81 -0
- data/lib/paperclip/storage.rb +3 -0
- data/lib/paperclip/storage/filesystem.rb +99 -0
- data/lib/paperclip/storage/fog.rb +252 -0
- data/lib/paperclip/storage/s3.rb +461 -0
- data/lib/paperclip/style.rb +106 -0
- data/lib/paperclip/tempfile.rb +42 -0
- data/lib/paperclip/tempfile_factory.rb +22 -0
- data/lib/paperclip/thumbnail.rb +131 -0
- data/lib/paperclip/url_generator.rb +76 -0
- data/lib/paperclip/validators.rb +73 -0
- data/lib/paperclip/validators/attachment_content_type_validator.rb +88 -0
- data/lib/paperclip/validators/attachment_file_name_validator.rb +75 -0
- data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +28 -0
- data/lib/paperclip/validators/attachment_presence_validator.rb +28 -0
- data/lib/paperclip/validators/attachment_size_validator.rb +109 -0
- data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +29 -0
- data/lib/paperclip/version.rb +3 -0
- data/lib/tasks/paperclip.rake +140 -0
- data/paperclip.gemspec +50 -0
- data/shoulda_macros/paperclip.rb +134 -0
- data/spec/database.yml +4 -0
- data/spec/paperclip/attachment_definitions_spec.rb +13 -0
- data/spec/paperclip/attachment_processing_spec.rb +79 -0
- data/spec/paperclip/attachment_registry_spec.rb +158 -0
- data/spec/paperclip/attachment_spec.rb +1590 -0
- data/spec/paperclip/content_type_detector_spec.rb +47 -0
- data/spec/paperclip/file_command_content_type_detector_spec.rb +40 -0
- data/spec/paperclip/filename_cleaner_spec.rb +13 -0
- data/spec/paperclip/geometry_detector_spec.rb +38 -0
- data/spec/paperclip/geometry_parser_spec.rb +73 -0
- data/spec/paperclip/geometry_spec.rb +255 -0
- data/spec/paperclip/glue_spec.rb +42 -0
- data/spec/paperclip/has_attached_file_spec.rb +78 -0
- data/spec/paperclip/integration_spec.rb +702 -0
- data/spec/paperclip/interpolations_spec.rb +270 -0
- data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +160 -0
- data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +140 -0
- data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +88 -0
- data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
- data/spec/paperclip/io_adapters/file_adapter_spec.rb +131 -0
- data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +137 -0
- data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
- data/spec/paperclip/io_adapters/nil_adapter_spec.rb +25 -0
- data/spec/paperclip/io_adapters/registry_spec.rb +35 -0
- data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +64 -0
- data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +146 -0
- data/spec/paperclip/io_adapters/uri_adapter_spec.rb +221 -0
- data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
- data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +108 -0
- data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
- data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
- data/spec/paperclip/media_type_spoof_detector_spec.rb +120 -0
- data/spec/paperclip/meta_class_spec.rb +30 -0
- data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +88 -0
- data/spec/paperclip/paperclip_spec.rb +196 -0
- data/spec/paperclip/plural_cache_spec.rb +37 -0
- data/spec/paperclip/processor_helpers_spec.rb +57 -0
- data/spec/paperclip/processor_spec.rb +26 -0
- data/spec/paperclip/rails_environment_spec.rb +30 -0
- data/spec/paperclip/rake_spec.rb +103 -0
- data/spec/paperclip/schema_spec.rb +252 -0
- data/spec/paperclip/storage/filesystem_spec.rb +79 -0
- data/spec/paperclip/storage/fog_spec.rb +560 -0
- data/spec/paperclip/storage/s3_live_spec.rb +188 -0
- data/spec/paperclip/storage/s3_spec.rb +1695 -0
- data/spec/paperclip/style_spec.rb +251 -0
- data/spec/paperclip/tempfile_factory_spec.rb +33 -0
- data/spec/paperclip/tempfile_spec.rb +35 -0
- data/spec/paperclip/thumbnail_spec.rb +504 -0
- data/spec/paperclip/url_generator_spec.rb +221 -0
- data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +322 -0
- data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +159 -0
- data/spec/paperclip/validators/attachment_presence_validator_spec.rb +85 -0
- data/spec/paperclip/validators/attachment_size_validator_spec.rb +235 -0
- data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +48 -0
- data/spec/paperclip/validators_spec.rb +164 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/support/assertions.rb +84 -0
- data/spec/support/fake_model.rb +24 -0
- data/spec/support/fake_rails.rb +12 -0
- data/spec/support/fixtures/12k.png +0 -0
- data/spec/support/fixtures/50x50.png +0 -0
- data/spec/support/fixtures/5k.png +0 -0
- data/spec/support/fixtures/animated +0 -0
- data/spec/support/fixtures/animated.gif +0 -0
- data/spec/support/fixtures/animated.unknown +0 -0
- data/spec/support/fixtures/bad.png +1 -0
- data/spec/support/fixtures/empty.html +1 -0
- data/spec/support/fixtures/empty.xlsx +0 -0
- data/spec/support/fixtures/fog.yml +8 -0
- data/spec/support/fixtures/rotated.jpg +0 -0
- data/spec/support/fixtures/s3.yml +8 -0
- data/spec/support/fixtures/spaced file.jpg +0 -0
- data/spec/support/fixtures/spaced file.png +0 -0
- data/spec/support/fixtures/text.txt +1 -0
- data/spec/support/fixtures/twopage.pdf +0 -0
- data/spec/support/fixtures/uppercase.PNG +0 -0
- data/spec/support/matchers/accept.rb +5 -0
- data/spec/support/matchers/exist.rb +5 -0
- data/spec/support/matchers/have_column.rb +23 -0
- data/spec/support/mock_attachment.rb +24 -0
- data/spec/support/mock_interpolator.rb +24 -0
- data/spec/support/mock_url_generator_builder.rb +26 -0
- data/spec/support/model_reconstruction.rb +72 -0
- data/spec/support/reporting.rb +11 -0
- data/spec/support/test_data.rb +13 -0
- data/spec/support/version_helper.rb +9 -0
- metadata +586 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
# require "spec_helper"
|
2
|
+
|
3
|
+
describe Paperclip::Glue do
|
4
|
+
describe "when ActiveRecord does not exist" do
|
5
|
+
before do
|
6
|
+
ActiveRecordSaved = ActiveRecord
|
7
|
+
Object.send :remove_const, "ActiveRecord"
|
8
|
+
end
|
9
|
+
|
10
|
+
after do
|
11
|
+
ActiveRecord = ActiveRecordSaved
|
12
|
+
Object.send :remove_const, "ActiveRecordSaved"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "does not fail" do
|
16
|
+
NonActiveRecordModel = Class.new
|
17
|
+
NonActiveRecordModel.include Paperclip::Glue
|
18
|
+
Object.send :remove_const, "NonActiveRecordModel"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "when ActiveRecord does exist" do
|
23
|
+
before do
|
24
|
+
if Object.const_defined?("ActiveRecord")
|
25
|
+
@defined_active_record = false
|
26
|
+
else
|
27
|
+
ActiveRecord = :defined
|
28
|
+
@defined_active_record = true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
after do
|
33
|
+
Object.send :remove_const, "ActiveRecord" if @defined_active_record
|
34
|
+
end
|
35
|
+
|
36
|
+
it "does not fail" do
|
37
|
+
NonActiveRecordModel = Class.new
|
38
|
+
NonActiveRecordModel.include Paperclip::Glue
|
39
|
+
Object.send :remove_const, "NonActiveRecordModel"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Paperclip::HasAttachedFile do
|
4
|
+
let(:a_class) { spy("Class") }
|
5
|
+
|
6
|
+
context "#define_on" do
|
7
|
+
it "defines a setter on the class object" do
|
8
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", {})
|
9
|
+
expect(a_class).to have_received(:define_method).with("avatar=")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "defines a getter on the class object" do
|
13
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", {})
|
14
|
+
expect(a_class).to have_received(:define_method).with("avatar")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "defines a query on the class object" do
|
18
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", {})
|
19
|
+
expect(a_class).to have_received(:define_method).with("avatar?")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "defines a method on the class to get all of its attachments" do
|
23
|
+
allow(a_class).to receive(:extend)
|
24
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", {})
|
25
|
+
expect(a_class).to have_received(:extend).with(Paperclip::HasAttachedFile::ClassMethods)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "flushes errors as part of validations" do
|
29
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", {})
|
30
|
+
expect(a_class).to have_received(:validates_each).with("avatar")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "registers the attachment with Paperclip::AttachmentRegistry" do
|
34
|
+
allow(Paperclip::AttachmentRegistry).to receive(:register)
|
35
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", size: 1)
|
36
|
+
expect(Paperclip::AttachmentRegistry).to have_received(:register).with(a_class, "avatar", size: 1)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "defines an after_save callback" do
|
40
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", {})
|
41
|
+
expect(a_class).to have_received("after_save")
|
42
|
+
end
|
43
|
+
|
44
|
+
it "defines a before_destroy callback" do
|
45
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", {})
|
46
|
+
expect(a_class).to have_received("before_destroy")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "defines an after_commit callback" do
|
50
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", {})
|
51
|
+
expect(a_class).to have_received("after_commit")
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when the class does not allow after_commit callbacks" do
|
55
|
+
it "defines an after_destroy callback" do
|
56
|
+
a_class = double("class", after_destroy: nil, validates_each: nil, define_method: nil, after_save: nil, before_destroy: nil, define_paperclip_callbacks: nil, validates_media_type_spoof_detection: nil)
|
57
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", {})
|
58
|
+
expect(a_class).to have_received("after_destroy")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it "defines the Paperclip-specific callbacks" do
|
63
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", validate_media_type: false)
|
64
|
+
expect(a_class).to_not have_received(:validates_media_type_spoof_detection)
|
65
|
+
expect(a_class).to have_received("define_paperclip_callbacks")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "does not define a media_type check if told not to" do
|
69
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", validate_media_type: false)
|
70
|
+
expect(a_class).to_not have_received(:validates_media_type_spoof_detection)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "does define a media_type check if told to" do
|
74
|
+
Paperclip::HasAttachedFile.define_on(a_class, "avatar", validate_media_type: true)
|
75
|
+
expect(a_class).to have_received(:validates_media_type_spoof_detection)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,702 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "open-uri"
|
3
|
+
|
4
|
+
describe "Paperclip" do
|
5
|
+
around do |example|
|
6
|
+
files_before = ObjectSpace.each_object(Tempfile).select do |file|
|
7
|
+
file.path && File.file?(file.path)
|
8
|
+
end
|
9
|
+
|
10
|
+
example.run
|
11
|
+
|
12
|
+
files_after = ObjectSpace.each_object(Tempfile).select do |file|
|
13
|
+
file.path && File.file?(file.path)
|
14
|
+
end
|
15
|
+
|
16
|
+
diff = files_after - files_before
|
17
|
+
expect(diff).to eq([]), "Leaked tempfiles: #{diff.inspect}"
|
18
|
+
end
|
19
|
+
|
20
|
+
context "Many models at once" do
|
21
|
+
before do
|
22
|
+
rebuild_model
|
23
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
24
|
+
# Deals with `Too many open files` error
|
25
|
+
dummies = Array.new(300) { Dummy.new avatar: @file }
|
26
|
+
Dummy.import dummies
|
27
|
+
# save attachment instances to run after hooks including tempfile cleanup
|
28
|
+
# since activerecord-import does not use our usually hooked-in hooks
|
29
|
+
# (such as after_save)
|
30
|
+
dummies.each { |dummy| dummy.avatar.save }
|
31
|
+
end
|
32
|
+
|
33
|
+
after { @file.close }
|
34
|
+
|
35
|
+
it "does not exceed the open file limit" do
|
36
|
+
assert_nothing_raised do
|
37
|
+
Dummy.all.each(&:avatar)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "An attachment" do
|
43
|
+
before do
|
44
|
+
rebuild_model styles: { thumb: "50x50#" }
|
45
|
+
@dummy = Dummy.new
|
46
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
47
|
+
@dummy.avatar = @file
|
48
|
+
assert @dummy.save
|
49
|
+
end
|
50
|
+
|
51
|
+
after { @file.close }
|
52
|
+
|
53
|
+
it "creates its thumbnails properly" do
|
54
|
+
assert_match(/\b50x50\b/, `identify "#{@dummy.avatar.path(:thumb)}"`)
|
55
|
+
end
|
56
|
+
|
57
|
+
context "reprocessing with unreadable original" do
|
58
|
+
before { File.chmod(0o000, @dummy.avatar.path) }
|
59
|
+
|
60
|
+
it "does not raise an error" do
|
61
|
+
assert_nothing_raised do
|
62
|
+
silence_stream(STDERR) do
|
63
|
+
@dummy.avatar.reprocess!
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "returns false" do
|
69
|
+
silence_stream(STDERR) do
|
70
|
+
assert !@dummy.avatar.reprocess!
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
after { File.chmod(0o644, @dummy.avatar.path) }
|
75
|
+
end
|
76
|
+
|
77
|
+
context "redefining its attachment styles" do
|
78
|
+
before do
|
79
|
+
Dummy.class_eval do
|
80
|
+
has_attached_file :avatar, styles: { thumb: "150x25#", dynamic: lambda { |_a| "50x50#" } }
|
81
|
+
end
|
82
|
+
@d2 = Dummy.find(@dummy.id)
|
83
|
+
@original_timestamp = @d2.avatar_updated_at
|
84
|
+
@d2.avatar.reprocess!
|
85
|
+
@d2.save
|
86
|
+
end
|
87
|
+
|
88
|
+
it "creates its thumbnails properly" do
|
89
|
+
assert_match(/\b150x25\b/, `identify "#{@dummy.avatar.path(:thumb)}"`)
|
90
|
+
assert_match(/\b50x50\b/, `identify "#{@dummy.avatar.path(:dynamic)}"`)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "changes the timestamp" do
|
94
|
+
assert_not_equal @original_timestamp, @d2.avatar_updated_at
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "Attachment" do
|
100
|
+
before do
|
101
|
+
@thumb_path = "tmp/public/system/dummies/avatars/000/000/001/thumb/5k.png"
|
102
|
+
File.delete(@thumb_path) if File.exist?(@thumb_path)
|
103
|
+
rebuild_model styles: { thumb: "50x50#" }
|
104
|
+
@dummy = Dummy.new
|
105
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
106
|
+
end
|
107
|
+
|
108
|
+
after { @file.close }
|
109
|
+
|
110
|
+
it "does not create the thumbnails upon saving when post-processing is disabled" do
|
111
|
+
@dummy.avatar.post_processing = false
|
112
|
+
@dummy.avatar = @file
|
113
|
+
assert @dummy.save
|
114
|
+
assert_file_not_exists @thumb_path
|
115
|
+
end
|
116
|
+
|
117
|
+
it "creates the thumbnails upon saving when post_processing is enabled" do
|
118
|
+
@dummy.avatar.post_processing = true
|
119
|
+
@dummy.avatar = @file
|
120
|
+
assert @dummy.save
|
121
|
+
assert_file_exists @thumb_path
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "Attachment with no generated thumbnails" do
|
126
|
+
before do
|
127
|
+
@thumb_small_path = "tmp/public/system/dummies/avatars/000/000/001/thumb_small/5k.png"
|
128
|
+
@thumb_large_path = "tmp/public/system/dummies/avatars/000/000/001/thumb_large/5k.png"
|
129
|
+
File.delete(@thumb_small_path) if File.exist?(@thumb_small_path)
|
130
|
+
File.delete(@thumb_large_path) if File.exist?(@thumb_large_path)
|
131
|
+
rebuild_model styles: { thumb_small: "50x50#", thumb_large: "60x60#" }
|
132
|
+
@dummy = Dummy.new
|
133
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
134
|
+
|
135
|
+
@dummy.avatar.post_processing = false
|
136
|
+
@dummy.avatar = @file
|
137
|
+
assert @dummy.save
|
138
|
+
@dummy.avatar.post_processing = true
|
139
|
+
end
|
140
|
+
|
141
|
+
after { @file.close }
|
142
|
+
|
143
|
+
it "allows us to create all thumbnails in one go" do
|
144
|
+
assert_file_not_exists(@thumb_small_path)
|
145
|
+
assert_file_not_exists(@thumb_large_path)
|
146
|
+
|
147
|
+
@dummy.avatar.reprocess!
|
148
|
+
|
149
|
+
assert_file_exists(@thumb_small_path)
|
150
|
+
assert_file_exists(@thumb_large_path)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "allows us to selectively create each thumbnail" do
|
154
|
+
skip <<-EXPLANATION
|
155
|
+
#reprocess! calls #assign which calls Paperclip.io_adapters.for
|
156
|
+
which creates the tempfile. #assign then calls #post_process_file which
|
157
|
+
calls MediaTypeSpoofDetectionValidator#validate_each which calls
|
158
|
+
Paperclip.io_adapters.for, which creates another tempfile. That first
|
159
|
+
tempfile is the one that leaks.
|
160
|
+
EXPLANATION
|
161
|
+
|
162
|
+
assert_file_not_exists(@thumb_small_path)
|
163
|
+
assert_file_not_exists(@thumb_large_path)
|
164
|
+
|
165
|
+
@dummy.avatar.reprocess! :thumb_small
|
166
|
+
assert_file_exists(@thumb_small_path)
|
167
|
+
assert_file_not_exists(@thumb_large_path)
|
168
|
+
|
169
|
+
@dummy.avatar.reprocess! :thumb_large
|
170
|
+
assert_file_exists(@thumb_large_path)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context "A model that modifies its original" do
|
175
|
+
before do
|
176
|
+
rebuild_model styles: { original: "2x2#" }
|
177
|
+
@dummy = Dummy.new
|
178
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
179
|
+
@dummy.avatar = @file
|
180
|
+
end
|
181
|
+
|
182
|
+
it "reports the file size of the processed file and not the original" do
|
183
|
+
assert_not_equal File.size(@file.path), @dummy.avatar.size
|
184
|
+
end
|
185
|
+
|
186
|
+
after do
|
187
|
+
@file.close
|
188
|
+
# save attachment instance to run after hooks (including tempfile cleanup)
|
189
|
+
@dummy.avatar.save
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context "A model with attachments scoped under an id" do
|
194
|
+
before do
|
195
|
+
rebuild_model styles: { large: "100x100",
|
196
|
+
medium: "50x50" },
|
197
|
+
path: ":rails_root/tmp/:id/:attachments/:style.:extension"
|
198
|
+
@dummy = Dummy.new
|
199
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
200
|
+
@dummy.avatar = @file
|
201
|
+
end
|
202
|
+
|
203
|
+
after { @file.close }
|
204
|
+
|
205
|
+
context "when saved" do
|
206
|
+
before do
|
207
|
+
@dummy.save
|
208
|
+
@saved_path = @dummy.avatar.path(:large)
|
209
|
+
end
|
210
|
+
|
211
|
+
it "has a large file in the right place" do
|
212
|
+
assert_file_exists(@dummy.avatar.path(:large))
|
213
|
+
end
|
214
|
+
|
215
|
+
context "and deleted" do
|
216
|
+
before do
|
217
|
+
@dummy.avatar.clear
|
218
|
+
@dummy.save
|
219
|
+
end
|
220
|
+
|
221
|
+
it "does not have a large file in the right place anymore" do
|
222
|
+
assert_file_not_exists(@saved_path)
|
223
|
+
end
|
224
|
+
|
225
|
+
it "does not have its next two parent directories" do
|
226
|
+
assert_file_not_exists(File.dirname(@saved_path))
|
227
|
+
assert_file_not_exists(File.dirname(File.dirname(@saved_path)))
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context "and deleted where the delete fails" do
|
232
|
+
it "does not die if an unexpected SystemCallError happens" do
|
233
|
+
allow(FileUtils).to receive(:rmdir).and_raise(Errno::EPIPE)
|
234
|
+
assert_nothing_raised do
|
235
|
+
@dummy.avatar.clear
|
236
|
+
@dummy.save
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
[0o00, 0o02, 0o22].each do |umask|
|
244
|
+
context "when the umask is #{umask}" do
|
245
|
+
before do
|
246
|
+
rebuild_model
|
247
|
+
@dummy = Dummy.new
|
248
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
249
|
+
@umask = File.umask(umask)
|
250
|
+
end
|
251
|
+
|
252
|
+
after do
|
253
|
+
File.umask @umask
|
254
|
+
@file.close
|
255
|
+
end
|
256
|
+
|
257
|
+
it "respects the current umask" do
|
258
|
+
@dummy.avatar = @file
|
259
|
+
@dummy.save
|
260
|
+
assert_equal 0o666 & ~umask, 0o666 & File.stat(@dummy.avatar.path).mode
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
[0o666, 0o664, 0o640].each do |perms|
|
266
|
+
context "when the perms are #{perms}" do
|
267
|
+
before do
|
268
|
+
rebuild_model override_file_permissions: perms
|
269
|
+
@dummy = Dummy.new
|
270
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
271
|
+
end
|
272
|
+
|
273
|
+
after do
|
274
|
+
@file.close
|
275
|
+
end
|
276
|
+
|
277
|
+
it "respects the current perms" do
|
278
|
+
@dummy.avatar = @file
|
279
|
+
@dummy.save
|
280
|
+
assert_equal perms, File.stat(@dummy.avatar.path).mode & 0o777
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
it "skips chmod operation, when override_file_permissions is set to false (e.g. useful when using CIFS mounts)" do
|
286
|
+
expect(FileUtils).to_not receive(:chmod)
|
287
|
+
|
288
|
+
rebuild_model override_file_permissions: false
|
289
|
+
dummy = Dummy.create!
|
290
|
+
dummy.avatar = @file
|
291
|
+
dummy.save
|
292
|
+
end
|
293
|
+
|
294
|
+
context "A model with a filesystem attachment" do
|
295
|
+
before do
|
296
|
+
rebuild_model styles: { large: "300x300>",
|
297
|
+
medium: "100x100",
|
298
|
+
thumb: ["32x32#", :gif] },
|
299
|
+
default_style: :medium,
|
300
|
+
url: "/:attachment/:class/:style/:id/:basename.:extension",
|
301
|
+
path: ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
302
|
+
@dummy = Dummy.new
|
303
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
304
|
+
@bad_file = File.new(fixture_file("bad.png"), "rb")
|
305
|
+
|
306
|
+
assert @dummy.avatar = @file
|
307
|
+
assert @dummy.valid?, @dummy.errors.full_messages.join(", ")
|
308
|
+
assert @dummy.save
|
309
|
+
end
|
310
|
+
|
311
|
+
after { [@file, @bad_file].each(&:close) }
|
312
|
+
|
313
|
+
it "writes and delete its files" do
|
314
|
+
[["434x66", :original],
|
315
|
+
["300x46", :large],
|
316
|
+
["100x15", :medium],
|
317
|
+
["32x32", :thumb]].each do |geo, style|
|
318
|
+
cmd = %[identify -format "%wx%h" "#{@dummy.avatar.path(style)}"]
|
319
|
+
assert_equal geo, `#{cmd}`.chomp, cmd
|
320
|
+
end
|
321
|
+
|
322
|
+
saved_paths = [:thumb, :medium, :large, :original].map { |s| @dummy.avatar.path(s) }
|
323
|
+
|
324
|
+
@d2 = Dummy.find(@dummy.id)
|
325
|
+
assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path}"`.chomp
|
326
|
+
assert_equal "434x66", `identify -format "%wx%h" "#{@d2.avatar.path(:original)}"`.chomp
|
327
|
+
assert_equal "300x46", `identify -format "%wx%h" "#{@d2.avatar.path(:large)}"`.chomp
|
328
|
+
assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path(:medium)}"`.chomp
|
329
|
+
assert_equal "32x32", `identify -format "%wx%h" "#{@d2.avatar.path(:thumb)}"`.chomp
|
330
|
+
|
331
|
+
assert @dummy.valid?
|
332
|
+
assert @dummy.save
|
333
|
+
|
334
|
+
saved_paths.each do |p|
|
335
|
+
assert_file_exists(p)
|
336
|
+
end
|
337
|
+
|
338
|
+
@dummy.avatar.clear
|
339
|
+
assert_nil @dummy.avatar_file_name
|
340
|
+
assert @dummy.valid?
|
341
|
+
assert @dummy.save
|
342
|
+
|
343
|
+
saved_paths.each do |p|
|
344
|
+
assert_file_not_exists(p)
|
345
|
+
end
|
346
|
+
|
347
|
+
@d2 = Dummy.find(@dummy.id)
|
348
|
+
assert_nil @d2.avatar_file_name
|
349
|
+
end
|
350
|
+
|
351
|
+
it "works exactly the same when new as when reloaded" do
|
352
|
+
@d2 = Dummy.find(@dummy.id)
|
353
|
+
|
354
|
+
assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
|
355
|
+
[:thumb, :medium, :large, :original].each do |style|
|
356
|
+
assert_equal @dummy.avatar.path(style), @d2.avatar.path(style)
|
357
|
+
end
|
358
|
+
|
359
|
+
saved_paths = [:thumb, :medium, :large, :original].map { |s| @dummy.avatar.path(s) }
|
360
|
+
|
361
|
+
@d2.avatar.clear
|
362
|
+
assert @d2.save
|
363
|
+
|
364
|
+
saved_paths.each do |p|
|
365
|
+
assert_file_not_exists(p)
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
it "does not abide things that don't have adapters" do
|
370
|
+
assert_raises(Paperclip::AdapterRegistry::NoHandlerError) do
|
371
|
+
@dummy.avatar = "not a file"
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
it "is not ok with bad files" do
|
376
|
+
@dummy.avatar = @bad_file
|
377
|
+
assert !@dummy.valid?
|
378
|
+
# save attachment instance to run after hooks (including tempfile cleanup)
|
379
|
+
@dummy.avatar.save
|
380
|
+
end
|
381
|
+
|
382
|
+
it "knows the difference between good files, bad files, and not files when validating" do
|
383
|
+
Dummy.validates_attachment_presence :avatar
|
384
|
+
@d2 = Dummy.find(@dummy.id)
|
385
|
+
@d2.avatar = @file
|
386
|
+
assert @d2.valid?, @d2.errors.full_messages.inspect
|
387
|
+
# save attachment instance to run after hooks (including tempfile cleanup)
|
388
|
+
@d2.avatar.save
|
389
|
+
|
390
|
+
@d2.avatar = @bad_file
|
391
|
+
assert !@d2.valid?
|
392
|
+
# save attachment instance to run after hooks (including tempfile cleanup)
|
393
|
+
@d2.avatar.save
|
394
|
+
end
|
395
|
+
|
396
|
+
it "is able to reload without saving and not have the file disappear" do
|
397
|
+
@dummy.avatar = @file
|
398
|
+
assert @dummy.save, @dummy.errors.full_messages.inspect
|
399
|
+
@dummy.avatar.clear
|
400
|
+
assert_nil @dummy.avatar_file_name
|
401
|
+
@dummy.reload
|
402
|
+
assert_equal "5k.png", @dummy.avatar_file_name
|
403
|
+
end
|
404
|
+
|
405
|
+
context "that is assigned its file from another Paperclip attachment" do
|
406
|
+
before do
|
407
|
+
@dummy2 = Dummy.new
|
408
|
+
@file2 = File.new(fixture_file("12k.png"), "rb")
|
409
|
+
assert @dummy2.avatar = @file2
|
410
|
+
@dummy2.save
|
411
|
+
end
|
412
|
+
|
413
|
+
after { @file2.close }
|
414
|
+
|
415
|
+
it "works when assigned a file" do
|
416
|
+
assert_not_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
|
417
|
+
`identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
|
418
|
+
|
419
|
+
assert @dummy.avatar = @dummy2.avatar
|
420
|
+
@dummy.save
|
421
|
+
assert_equal @dummy.avatar_file_name, @dummy2.avatar_file_name
|
422
|
+
assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
|
423
|
+
`identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
context "A model with an attachments association and a Paperclip attachment" do
|
429
|
+
before do
|
430
|
+
Dummy.class_eval do
|
431
|
+
has_many :attachments, class_name: "Dummy"
|
432
|
+
end
|
433
|
+
|
434
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
435
|
+
@dummy = Dummy.new
|
436
|
+
@dummy.avatar = @file
|
437
|
+
end
|
438
|
+
|
439
|
+
after { @file.close }
|
440
|
+
|
441
|
+
it "does not error when saving" do
|
442
|
+
@dummy.save!
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
context "A model with an attachment with hash in file name" do
|
447
|
+
before do
|
448
|
+
@settings = { styles: { thumb: "50x50#" },
|
449
|
+
path: ":rails_root/public/system/:attachment/:id_partition/:style/:hash.:extension",
|
450
|
+
url: "/system/:attachment/:id_partition/:style/:hash.:extension",
|
451
|
+
hash_secret: "somesecret" }
|
452
|
+
|
453
|
+
rebuild_model @settings
|
454
|
+
|
455
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
456
|
+
@dummy = Dummy.create! avatar: @file
|
457
|
+
end
|
458
|
+
|
459
|
+
after do
|
460
|
+
@file.close
|
461
|
+
end
|
462
|
+
|
463
|
+
it "is accessible" do
|
464
|
+
assert_file_exists(@dummy.avatar.path(:original))
|
465
|
+
assert_file_exists(@dummy.avatar.path(:thumb))
|
466
|
+
end
|
467
|
+
|
468
|
+
context "when new style is added" do
|
469
|
+
before do
|
470
|
+
@dummy.avatar.options[:styles][:mini] = "25x25#"
|
471
|
+
@dummy.avatar.instance_variable_set :@normalized_styles, nil
|
472
|
+
allow(Time).to receive(:now).and_return(Time.now + 10)
|
473
|
+
@dummy.avatar.reprocess!
|
474
|
+
@dummy.reload
|
475
|
+
end
|
476
|
+
|
477
|
+
it "makes all the styles accessible" do
|
478
|
+
assert_file_exists(@dummy.avatar.path(:original))
|
479
|
+
assert_file_exists(@dummy.avatar.path(:thumb))
|
480
|
+
assert_file_exists(@dummy.avatar.path(:mini))
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
if ENV["S3_BUCKET"]
|
486
|
+
def s3_files_for(attachment)
|
487
|
+
[:thumb, :medium, :large, :original].inject({}) do |files, style|
|
488
|
+
data = `curl "#{attachment.url(style)}" 2>/dev/null`.chomp
|
489
|
+
t = Tempfile.new("paperclip-test")
|
490
|
+
t.binmode
|
491
|
+
t.write(data)
|
492
|
+
t.rewind
|
493
|
+
files[style] = t
|
494
|
+
files
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
def s3_headers_for(attachment, style)
|
499
|
+
`curl --head "#{attachment.url(style)}" 2>/dev/null`.split("\n").inject({}) do |h, head|
|
500
|
+
split_head = head.chomp.split(/\s*:\s*/, 2)
|
501
|
+
h[split_head.first.downcase] = split_head.last unless split_head.empty?
|
502
|
+
h
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
context "A model with an S3 attachment" do
|
507
|
+
before do
|
508
|
+
rebuild_model(
|
509
|
+
styles: {
|
510
|
+
large: "300x300>",
|
511
|
+
medium: "100x100",
|
512
|
+
thumb: ["32x32#", :gif],
|
513
|
+
custom: {
|
514
|
+
geometry: "32x32#",
|
515
|
+
s3_headers: { "Cache-Control" => "max-age=31557600" },
|
516
|
+
s3_metadata: { "foo" => "bar" }
|
517
|
+
}
|
518
|
+
},
|
519
|
+
storage: :s3,
|
520
|
+
s3_credentials: File.new(fixture_file("s3.yml")),
|
521
|
+
s3_options: { logger: Paperclip.logger },
|
522
|
+
default_style: :medium,
|
523
|
+
bucket: ENV["S3_BUCKET"],
|
524
|
+
path: ":class/:attachment/:id/:style/:basename.:extension"
|
525
|
+
)
|
526
|
+
|
527
|
+
@dummy = Dummy.new
|
528
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
529
|
+
@bad_file = File.new(fixture_file("bad.png"), "rb")
|
530
|
+
|
531
|
+
@dummy.avatar = @file
|
532
|
+
@dummy.valid?
|
533
|
+
@dummy.save!
|
534
|
+
|
535
|
+
@files_on_s3 = s3_files_for(@dummy.avatar)
|
536
|
+
end
|
537
|
+
|
538
|
+
after do
|
539
|
+
@file.close
|
540
|
+
@bad_file.close
|
541
|
+
@files_on_s3.values.each(&:close) if @files_on_s3
|
542
|
+
end
|
543
|
+
|
544
|
+
context "assigning itself to a new model" do
|
545
|
+
before do
|
546
|
+
@d2 = Dummy.new
|
547
|
+
@d2.avatar = @dummy.avatar
|
548
|
+
@d2.save
|
549
|
+
end
|
550
|
+
|
551
|
+
it "has the same name as the old file" do
|
552
|
+
assert_equal @d2.avatar.original_filename, @dummy.avatar.original_filename
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
it "has the same contents as the original" do
|
557
|
+
assert_equal @file.read, @files_on_s3[:original].read
|
558
|
+
end
|
559
|
+
|
560
|
+
it "writes and delete its files" do
|
561
|
+
[["434x66", :original],
|
562
|
+
["300x46", :large],
|
563
|
+
["100x15", :medium],
|
564
|
+
["32x32", :thumb]].each do |geo, style|
|
565
|
+
cmd = %[identify -format "%wx%h" "#{@files_on_s3[style].path}"]
|
566
|
+
assert_equal geo, `#{cmd}`.chomp, cmd
|
567
|
+
end
|
568
|
+
|
569
|
+
@d2 = Dummy.find(@dummy.id)
|
570
|
+
@d2_files = s3_files_for @d2.avatar
|
571
|
+
[["434x66", :original],
|
572
|
+
["300x46", :large],
|
573
|
+
["100x15", :medium],
|
574
|
+
["32x32", :thumb]].each do |geo, style|
|
575
|
+
cmd = %[identify -format "%wx%h" "#{@d2_files[style].path}"]
|
576
|
+
assert_equal geo, `#{cmd}`.chomp, cmd
|
577
|
+
end
|
578
|
+
|
579
|
+
@dummy.avatar.clear
|
580
|
+
assert_nil @dummy.avatar_file_name
|
581
|
+
assert @dummy.valid?
|
582
|
+
assert @dummy.save
|
583
|
+
|
584
|
+
[:thumb, :medium, :large, :original].each do |style|
|
585
|
+
assert !@dummy.avatar.exists?(style)
|
586
|
+
end
|
587
|
+
|
588
|
+
@d2 = Dummy.find(@dummy.id)
|
589
|
+
assert_nil @d2.avatar_file_name
|
590
|
+
end
|
591
|
+
|
592
|
+
it "works exactly the same when new as when reloaded" do
|
593
|
+
@d2 = Dummy.find(@dummy.id)
|
594
|
+
|
595
|
+
assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
|
596
|
+
|
597
|
+
[:thumb, :medium, :large, :original].each do |style|
|
598
|
+
begin
|
599
|
+
first_file = open(@dummy.avatar.url(style))
|
600
|
+
second_file = open(@dummy.avatar.url(style))
|
601
|
+
assert_equal first_file.read, second_file.read
|
602
|
+
ensure
|
603
|
+
first_file.close if first_file
|
604
|
+
second_file.close if second_file
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
@d2.avatar.clear
|
609
|
+
assert @d2.save
|
610
|
+
|
611
|
+
[:thumb, :medium, :large, :original].each do |style|
|
612
|
+
assert !@dummy.avatar.exists?(style)
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
it "knows the difference between good files, bad files, and nil" do
|
617
|
+
@dummy.avatar = @bad_file
|
618
|
+
assert !@dummy.valid?
|
619
|
+
@dummy.avatar = nil
|
620
|
+
assert @dummy.valid?
|
621
|
+
|
622
|
+
Dummy.validates_attachment_presence :avatar
|
623
|
+
@d2 = Dummy.find(@dummy.id)
|
624
|
+
@d2.avatar = @file
|
625
|
+
assert @d2.valid?
|
626
|
+
@d2.avatar = @bad_file
|
627
|
+
assert !@d2.valid?
|
628
|
+
@d2.avatar = nil
|
629
|
+
assert !@d2.valid?
|
630
|
+
end
|
631
|
+
|
632
|
+
it "is able to reload without saving and not have the file disappear" do
|
633
|
+
@dummy.avatar = @file
|
634
|
+
assert @dummy.save
|
635
|
+
@dummy.avatar = nil
|
636
|
+
assert_nil @dummy.avatar_file_name
|
637
|
+
@dummy.reload
|
638
|
+
assert_equal "5k.png", @dummy.avatar_file_name
|
639
|
+
end
|
640
|
+
|
641
|
+
it "has the right content type" do
|
642
|
+
headers = s3_headers_for(@dummy.avatar, :original)
|
643
|
+
assert_equal "image/png", headers["content-type"]
|
644
|
+
end
|
645
|
+
|
646
|
+
it "has the right style-specific headers" do
|
647
|
+
headers = s3_headers_for(@dummy.avatar, :custom)
|
648
|
+
assert_equal "max-age=31557600", headers["cache-control"]
|
649
|
+
end
|
650
|
+
|
651
|
+
it "has the right style-specific metadata" do
|
652
|
+
headers = s3_headers_for(@dummy.avatar, :custom)
|
653
|
+
assert_equal "bar", headers["x-amz-meta-foo"]
|
654
|
+
end
|
655
|
+
|
656
|
+
context "with non-english character in the file name" do
|
657
|
+
before do
|
658
|
+
allow(@file).to receive(:original_filename).and_return("クリップ.png")
|
659
|
+
@dummy.avatar = @file
|
660
|
+
end
|
661
|
+
|
662
|
+
it "does not raise any error" do
|
663
|
+
@dummy.save!
|
664
|
+
end
|
665
|
+
end
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
context "Copying attachments between models" do
|
670
|
+
before do
|
671
|
+
rebuild_model
|
672
|
+
@file = File.new(fixture_file("5k.png"), "rb")
|
673
|
+
end
|
674
|
+
|
675
|
+
after { @file.close }
|
676
|
+
|
677
|
+
it "succeeds when original attachment is a file" do
|
678
|
+
original = Dummy.new
|
679
|
+
original.avatar = @file
|
680
|
+
assert original.save
|
681
|
+
|
682
|
+
copy = Dummy.new
|
683
|
+
copy.avatar = original.avatar
|
684
|
+
assert copy.save
|
685
|
+
|
686
|
+
assert copy.avatar.present?
|
687
|
+
end
|
688
|
+
|
689
|
+
it "succeeds when original attachment is empty" do
|
690
|
+
original = Dummy.create!
|
691
|
+
|
692
|
+
copy = Dummy.new
|
693
|
+
copy.avatar = @file
|
694
|
+
assert copy.save
|
695
|
+
assert copy.avatar.present?
|
696
|
+
|
697
|
+
copy.avatar = original.avatar
|
698
|
+
assert copy.save
|
699
|
+
assert !copy.avatar.present?
|
700
|
+
end
|
701
|
+
end
|
702
|
+
end
|