Fix Active Storage behavior on record dup

Prior to this commit, a `dup`ed record and its originating record would
share the same `Attached` proxy objects.  Those proxy objects, in turn,
would point to the same `Attachment` associations, causing changes made
through the proxy interface to affect both records.
This commit is contained in:
Jonathan Hefner 2020-05-25 21:03:32 -05:00 committed by GitHub
parent 803c030144
commit d02d259b61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 2 deletions

View File

@ -46,7 +46,8 @@ module ActiveStorage
generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
# frozen_string_literal: true
def #{name}
@active_storage_attached_#{name} ||= ActiveStorage::Attached::One.new("#{name}", self)
@active_storage_attached ||= {}
@active_storage_attached[:#{name}] ||= ActiveStorage::Attached::One.new("#{name}", self)
end
def #{name}=(attachable)
@ -116,7 +117,8 @@ module ActiveStorage
generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
# frozen_string_literal: true
def #{name}
@active_storage_attached_#{name} ||= ActiveStorage::Attached::Many.new("#{name}", self)
@active_storage_attached ||= {}
@active_storage_attached[:#{name}] ||= ActiveStorage::Attached::Many.new("#{name}", self)
end
def #{name}=(attachables)
@ -183,6 +185,12 @@ module ActiveStorage
super || attachment_changes.any?
end
def initialize_dup(*) #:nodoc:
super
@active_storage_attached = nil
@attachment_changes = nil
end
def reload(*) #:nodoc:
super.tap { @attachment_changes = nil }
end

View File

@ -552,6 +552,20 @@ class ActiveStorage::ManyAttachedTest < ActiveSupport::TestCase
end
end
test "duped record does not share attachments" do
@user.highlights.attach [ create_blob(filename: "funky.jpg") ]
assert_not_equal @user.highlights.first, @user.dup.highlights.first
end
test "duped record does not share attachment changes" do
@user.highlights.attach [ create_blob(filename: "funky.jpg") ]
assert_not_predicate @user, :changed_for_autosave?
@user.dup.highlights.attach [ create_blob(filename: "town.mp4") ]
assert_not_predicate @user, :changed_for_autosave?
end
test "clearing change on reload" do
@user.highlights = [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ]
assert @user.highlights.attached?

View File

@ -529,6 +529,20 @@ class ActiveStorage::OneAttachedTest < ActiveSupport::TestCase
end
end
test "duped record does not share attachments" do
@user.avatar.attach create_blob(filename: "funky.jpg")
assert_not_equal @user.avatar.attachment, @user.dup.avatar.attachment
end
test "duped record does not share attachment changes" do
@user.avatar.attach create_blob(filename: "funky.jpg")
assert_not_predicate @user, :changed_for_autosave?
@user.dup.avatar.attach create_blob(filename: "town.jpg")
assert_not_predicate @user, :changed_for_autosave?
end
test "clearing change on reload" do
@user.avatar = create_blob(filename: "funky.jpg")
assert @user.avatar.attached?