Skip to content

Commit 7b2ce50

Browse files
committed
Fix failing to remove existing files on updating by #remove_#{column}=, ##{column}_cache=, and #remote_#{column}_url=
Fixes #2778, Fixes #2779
1 parent 9001ab7 commit 7b2ce50

File tree

4 files changed

+151
-16
lines changed

4 files changed

+151
-16
lines changed

lib/carrierwave/mounter.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ def blank?
168168
end
169169

170170
def remove=(value)
171+
uploaders # Ensure that uploaders are initialized based on the current value
171172
@remove = value
172173
write_temporary_identifier
173174
end
@@ -220,7 +221,7 @@ def option(name)
220221
end
221222

222223
def clear_unstaged
223-
@uploaders ||= []
224+
uploaders # Ensure that uploaders are initialized based on the current value
224225
staged, unstaged = @uploaders.partition(&:staged)
225226
@uploaders = staged
226227
@removed_uploaders += unstaged

spec/mount_multiple_spec.rb

+44-15
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,15 @@ def monkey
541541
expect(instance.images[0].current_path).to match(/test.jpg$/)
542542
end
543543
end
544+
545+
context "when a file is already stored" do
546+
before { allow(instance).to receive(:read_uploader).and_return(['bork.txt']) }
547+
548+
it "marks the previously uploaded file as removed" do
549+
instance.images_cache = ['1369894322-123-0123-1234/test.jpg'].to_json
550+
expect(instance.send(:_mounter, :images).instance_variable_get(:@removed_uploaders).map(&:identifier)).to eq ['bork.txt']
551+
end
552+
end
544553
end
545554

546555
describe "#remote_images_urls" do
@@ -565,25 +574,24 @@ def monkey
565574
before do
566575
stub_request(:get, "http://www.example.com/#{test_file_name}").to_return(body: File.read(test_file_stub))
567576
stub_request(:get, "http://www.example.com/test.txt").to_return(status: 404)
568-
instance.remote_images_urls = remote_images_url
569577
end
570578

571579
context "does nothing when nil is assigned" do
572-
let(:remote_images_url) { nil }
580+
before { instance.remote_images_urls = nil }
573581

574582
it { is_expected.to be_empty }
575583
end
576584

577585
context "does nothing when an empty string is assigned" do
578-
let(:remote_images_url) { '' }
586+
before { instance.remote_images_urls = '' }
579587

580588
it { is_expected.to be_empty }
581589
end
582590

583591
context "retrieves from cache when a cache name is assigned" do
584592
subject { images[0].current_path }
585593

586-
let(:remote_images_url) { ["http://www.example.com/test.jpg"] }
594+
before { instance.remote_images_urls = ["http://www.example.com/test.jpg"] }
587595

588596
it { is_expected.to match(/test.jpg$/) }
589597

@@ -595,12 +603,10 @@ def monkey
595603
context "writes over a previously stored file" do
596604
subject { images[0].current_path }
597605

598-
let(:remote_images_url) { ["http://www.example.com/test.jpg"] }
599-
600606
before do
601607
instance.images = [stub_file("portrait.jpg")]
602608
instance.store_images!
603-
instance.remote_images_urls = remote_images_url
609+
instance.remote_images_urls = ["http://www.example.com/test.jpg"]
604610
end
605611

606612
it { is_expected.to match(/test.jpg$/) }
@@ -609,11 +615,9 @@ def monkey
609615
context "does not write over a previously assigned file" do
610616
subject { images[0].current_path }
611617

612-
let(:remote_images_url) { ["http://www.example.com/test.jpg"] }
613-
614618
before do
615619
instance.images = [stub_file("portrait.jpg")]
616-
instance.remote_images_urls = remote_images_url
620+
instance.remote_images_urls = ["http://www.example.com/test.jpg"]
617621
end
618622

619623
it { is_expected.to match(/portrait.jpg$/) }
@@ -622,12 +626,10 @@ def monkey
622626
context "when an empty string is assigned" do
623627
subject { images[0].current_path }
624628

625-
let(:remote_images_url) { [""] }
626-
627629
before do
628630
instance.images = [stub_file("portrait.jpg")]
629631
instance.store_images!
630-
instance.remote_images_urls = remote_images_url
632+
instance.remote_images_urls = [""]
631633
end
632634

633635
it "does not write over a previously stored file" do
@@ -636,7 +638,7 @@ def monkey
636638
end
637639

638640
context "if a file fails to be downloaded" do
639-
let(:remote_images_url) { ["http://www.example.com/test.txt", "http://www.example.com/test.jpg"] }
641+
before { instance.remote_images_urls = ["http://www.example.com/test.txt", "http://www.example.com/test.jpg"] }
640642

641643
it "keeps files which was downloaded successfully" do
642644
expect(instance.images.map(&:identifier)).to eq ['test.jpg']
@@ -645,14 +647,25 @@ def monkey
645647

646648
context "clears the unsaved remote urls when nil is assigned" do
647649
subject { instance.remote_images_urls }
648-
let(:remote_images_url) { ['invalid'] }
650+
before { instance.remote_images_urls = ['invalid'] }
649651

650652
before do
651653
instance.remote_images_urls = nil
652654
end
653655

654656
it { is_expected.to be_empty }
655657
end
658+
659+
context "when a file is already stored" do
660+
before do
661+
allow(instance).to receive(:read_uploader).and_return(['bork.txt'])
662+
instance.remote_images_urls = ["http://www.example.com/test.jpg"]
663+
end
664+
665+
it "marks the previously uploaded file as removed" do
666+
expect(instance.send(:_mounter, :images).instance_variable_get(:@removed_uploaders).map(&:identifier)).to eq ['bork.txt']
667+
end
668+
end
656669
end
657670

658671
describe '#store_images!' do
@@ -716,6 +729,22 @@ def monkey
716729
end
717730
end
718731

732+
describe '#remove_images=' do
733+
context "when a file is already stored" do
734+
before do
735+
attribute = ['bork.txt']
736+
allow(instance).to receive(:read_uploader) { attribute }
737+
allow(instance).to receive(:write_uploader) { |_, value| attribute.replace(value || []) }
738+
end
739+
740+
it "marks the previously uploaded file as removed" do
741+
instance.remove_images = true
742+
instance.write_images_identifier
743+
expect(instance.send(:_mounter, :images).instance_variable_get(:@removed_uploaders).map(&:identifier)).to eq ['bork.txt']
744+
end
745+
end
746+
end
747+
719748
describe '#remove_images?' do
720749
subject { instance.remove_images? }
721750

spec/mount_single_spec.rb

+23
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,12 @@ def default_url
304304
@instance.image_cache = ''
305305
expect(@instance.image.current_path).to match(/test.jpg$/)
306306
end
307+
308+
it "marks the previously uploaded file as removed" do
309+
allow(@instance).to receive(:read_uploader).and_return('bork.txt')
310+
@instance.image_cache = '1369894322-123-0123-1234/test.jpg'
311+
expect(@instance.send(:_mounter, :image).instance_variable_get(:@removed_uploaders).map(&:identifier)).to eq ['bork.txt']
312+
end
307313
end
308314

309315
describe "#remote_image_url" do
@@ -384,6 +390,12 @@ def default_url
384390

385391
expect(@instance.remote_image_url).to be_nil
386392
end
393+
394+
it "marks the previously uploaded file as removed" do
395+
allow(@instance).to receive(:read_uploader).and_return('bork.txt')
396+
@instance.remote_image_url = "http://www.example.com/test.jpg"
397+
expect(@instance.send(:_mounter, :image).instance_variable_get(:@removed_uploaders).map(&:identifier)).to eq ['bork.txt']
398+
end
387399
end
388400

389401
describe '#store_image!' do
@@ -452,6 +464,17 @@ def default_url
452464

453465
end
454466

467+
describe '#remove_image=' do
468+
it "marks the previously uploaded file as removed" do
469+
@attribute = 'bork.txt'
470+
allow(@instance).to receive(:read_uploader) { @attribute }
471+
allow(@instance).to receive(:write_uploader) { |_, value| @attribute = value }
472+
@instance.remove_image = true
473+
@instance.write_image_identifier
474+
expect(@instance.send(:_mounter, :image).instance_variable_get(:@removed_uploaders).map(&:identifier)).to eq ['bork.txt']
475+
end
476+
end
477+
455478
describe '#remove_image?' do
456479

457480
it "should be true when the value is truthy" do

spec/orm/activerecord_spec.rb

+82
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,37 @@ def monkey
548548
@event.remove_image?
549549
}.from(true).to(false)
550550
end
551+
552+
it "should remove the existing image file" do
553+
# Use another instance to simulate the real use case
554+
@another = Event.find(@event.id)
555+
@another.remove_image = true
556+
@another.save!
557+
expect(@event.image.file).not_to exist
558+
end
559+
end
560+
561+
describe "image_cache=" do
562+
let(:cache_id) { Event.new(image: stub_file('test.jpg')).image_cache }
563+
564+
before do
565+
end
566+
567+
it "sets the cached image" do
568+
@event.image_cache = cache_id
569+
@event.save!
570+
expect(@event.image.to_s).to eq '/uploads/test.jpg'
571+
end
572+
573+
it "removes the previous image file on save" do
574+
@event.image = stub_file('test.jpeg')
575+
@event.save!
576+
# Use another instance to simulate the real use case
577+
@another = Event.find(@event.id)
578+
@another.image_cache = cache_id
579+
@another.save!
580+
expect(@event.image.file).not_to exist
581+
end
551582
end
552583

553584
describe "#remote_image_url=" do
@@ -575,6 +606,16 @@ def monkey
575606
expect(@event.errors).to be_empty
576607
end
577608

609+
it "should remove the existing image" do
610+
@event.image = stub_file('test.jpeg')
611+
@event.save!
612+
# Use another instance to simulate the real use case
613+
@another = Event.find(@event.id)
614+
@another.remote_image_url = 'http://www.example.com/test.jpg'
615+
@another.save!
616+
expect(@event.image.file).not_to exist
617+
end
618+
578619
context 'when validating download' do
579620
before do
580621
@uploader.class_eval do
@@ -1567,6 +1608,37 @@ def monkey
15671608
@event.remove_images?
15681609
}.from(true).to(false)
15691610
end
1611+
1612+
it "should remove the existing image file" do
1613+
# Use another instance to simulate the real use case
1614+
@another = Event.find(@event.id)
1615+
@another.remove_images = true
1616+
@another.save!
1617+
expect(@event.images.first.file).not_to exist
1618+
end
1619+
end
1620+
1621+
describe "images_cache=" do
1622+
let(:cache_id) { Event.new(images: [stub_file('test.jpg')]).images_cache }
1623+
1624+
before do
1625+
end
1626+
1627+
it "sets the cached image" do
1628+
@event.images_cache = cache_id
1629+
@event.save!
1630+
expect(@event.images.first.to_s).to eq '/uploads/test.jpg'
1631+
end
1632+
1633+
it "removes the previous image file on save" do
1634+
@event.images = [stub_file('test.jpeg')]
1635+
@event.save!
1636+
# Use another instance to simulate the real use case
1637+
@another = Event.find(@event.id)
1638+
@another.images_cache = cache_id
1639+
@another.save!
1640+
expect(@event.images.first.file).not_to exist
1641+
end
15701642
end
15711643

15721644
describe "#remote_images_urls=" do
@@ -1594,6 +1666,16 @@ def monkey
15941666
expect(@event.errors).to be_empty
15951667
end
15961668

1669+
it "should remove the existing image" do
1670+
@event.images = [stub_file('test.jpeg')]
1671+
@event.save!
1672+
# Use another instance to simulate the real use case
1673+
@another = Event.find(@event.id)
1674+
@another.remote_images_urls = ['http://www.example.com/test.jpg']
1675+
@another.save!
1676+
expect(@event.images.first.file).not_to exist
1677+
end
1678+
15971679
context 'when validating download' do
15981680
before do
15991681
@uploader.class_eval do

0 commit comments

Comments
 (0)