From bf43c6de28f4b6d58fa8c2d4ec22747db4e44e60 Mon Sep 17 00:00:00 2001 From: Reid Beels Date: Sun, 17 Sep 2023 00:43:55 -0700 Subject: [PATCH] Duplicate the context hash when duplicating an Attacher (#653) Without this change, a single context hash is shared between the original attacher and its duplicate. The changes in fc6a3ed70aab9bff51ec1f0d269ad9553f4b8145 update this shared hash after duplication to reference the duplicate model, leading to both the duplicate and original attacher having `context[:record]` pointing at the duplicated model. --- lib/shrine/attacher.rb | 7 +++++++ test/attacher_test.rb | 7 +++++++ test/plugin/model_test.rb | 1 + 3 files changed, 15 insertions(+) diff --git a/lib/shrine/attacher.rb b/lib/shrine/attacher.rb index c7e4c143b..f90914778 100644 --- a/lib/shrine/attacher.rb +++ b/lib/shrine/attacher.rb @@ -341,6 +341,13 @@ def shrine_class private + # The copy constructor that's called on #dup and #clone + # We need to duplicate the context to prevent it from being shared + def initialize_copy(other) + super + @context = @context.dup + end + # Converts a String or Hash value into an UploadedFile object and ensures # it's uploaded to temporary storage. # diff --git a/test/attacher_test.rb b/test/attacher_test.rb index eff885d32..e7f3bcf64 100644 --- a/test/attacher_test.rb +++ b/test/attacher_test.rb @@ -6,6 +6,13 @@ @shrine = @attacher.shrine_class end + describe '#initialize_copy' do + it 'duplicates the context when duplicating the attacher' do + attacher_copy = @attacher.dup + refute_equal @attacher.context.object_id, attacher_copy.context.object_id + end + end + describe ".from_data" do it "instantiates an attacher from file data" do file = @attacher.upload(fakeio) diff --git a/test/plugin/model_test.rb b/test/plugin/model_test.rb index e33b0f2f0..4a446d273 100644 --- a/test/plugin/model_test.rb +++ b/test/plugin/model_test.rb @@ -136,6 +136,7 @@ assert_equal model_copy, model_copy.file_attacher.record assert_equal :file, model_copy.file_attacher.name assert_equal Hash[record: model_copy, name: :file], model_copy.file_attacher.context + assert_equal Hash[record: model, name: :file], model.file_attacher.context assert model_copy.file_attacher.changed? # retains any state end