mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
15d5b7589a
fixes #41862 ActiveStorage#has_many_attached with `config.active_storage.replace_on_assign_to_many = false` flag set to flase always appends new attachments to the association. As mentioned in the issue, if you use nested attributes along with flag disabled and mark some of the attachment to be `destroyed?`. The attachment is destroyed but get re-created without blob upload. This also results in `ActiveStorage#purge_job` failing with rollback. This PR intends to resolve the issue by checking if the attachment is persisted when `#save` is invoked. Only persisted and attachment records are saved which patches the issues.
142 lines
5.4 KiB
Ruby
142 lines
5.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
ENV["RAILS_ENV"] ||= "test"
|
|
require_relative "dummy/config/environment.rb"
|
|
|
|
require "bundler/setup"
|
|
require "active_support"
|
|
require "active_support/test_case"
|
|
require "active_support/core_ext/object/try"
|
|
require "active_support/testing/autorun"
|
|
require "active_support/configuration_file"
|
|
require "active_storage/service/mirror_service"
|
|
require "image_processing/mini_magick"
|
|
|
|
begin
|
|
require "byebug"
|
|
rescue LoadError
|
|
end
|
|
|
|
require "active_job"
|
|
ActiveJob::Base.queue_adapter = :test
|
|
ActiveJob::Base.logger = ActiveSupport::Logger.new(nil)
|
|
|
|
SERVICE_CONFIGURATIONS = begin
|
|
ActiveSupport::ConfigurationFile.parse(File.expand_path("service/configurations.yml", __dir__)).deep_symbolize_keys
|
|
rescue Errno::ENOENT
|
|
puts "Missing service configuration file in test/service/configurations.yml"
|
|
{}
|
|
end
|
|
|
|
require "tmpdir"
|
|
|
|
Rails.configuration.active_storage.service_configurations = SERVICE_CONFIGURATIONS.merge(
|
|
"local" => { "service" => "Disk", "root" => Dir.mktmpdir("active_storage_tests") },
|
|
"local_public" => { "service" => "Disk", "root" => Dir.mktmpdir("active_storage_tests"), "public" => true },
|
|
"disk_mirror_1" => { "service" => "Disk", "root" => Dir.mktmpdir("active_storage_tests_1") },
|
|
"disk_mirror_2" => { "service" => "Disk", "root" => Dir.mktmpdir("active_storage_tests_2") },
|
|
"disk_mirror_3" => { "service" => "Disk", "root" => Dir.mktmpdir("active_storage_tests_3") },
|
|
"mirror" => { "service" => "Mirror", "primary" => "local", "mirrors" => ["disk_mirror_1", "disk_mirror_2", "disk_mirror_3"] }
|
|
).deep_stringify_keys
|
|
|
|
Rails.configuration.active_storage.service = "local"
|
|
|
|
ActiveStorage.logger = ActiveSupport::Logger.new(nil)
|
|
ActiveStorage.verifier = ActiveSupport::MessageVerifier.new("Testing")
|
|
ActiveStorage::FixtureSet.file_fixture_path = File.expand_path("fixtures/files", __dir__)
|
|
|
|
class ActiveSupport::TestCase
|
|
self.file_fixture_path = ActiveStorage::FixtureSet.file_fixture_path
|
|
|
|
include ActiveRecord::TestFixtures
|
|
|
|
self.fixture_path = File.expand_path("fixtures", __dir__)
|
|
|
|
setup do
|
|
ActiveStorage::Current.host = "https://example.com"
|
|
end
|
|
|
|
teardown do
|
|
ActiveStorage::Current.reset
|
|
end
|
|
|
|
private
|
|
def create_blob(key: nil, data: "Hello world!", filename: "hello.txt", content_type: "text/plain", identify: true, service_name: nil, record: nil)
|
|
ActiveStorage::Blob.create_and_upload! key: key, io: StringIO.new(data), filename: filename, content_type: content_type, identify: identify, service_name: service_name, record: record
|
|
end
|
|
|
|
def create_file_blob(key: nil, filename: "racecar.jpg", content_type: "image/jpeg", metadata: nil, service_name: nil, record: nil)
|
|
ActiveStorage::Blob.create_and_upload! io: file_fixture(filename).open, filename: filename, content_type: content_type, metadata: metadata, service_name: service_name, record: record
|
|
end
|
|
|
|
def create_blob_before_direct_upload(key: nil, filename: "hello.txt", byte_size:, checksum:, content_type: "text/plain", record: nil)
|
|
ActiveStorage::Blob.create_before_direct_upload! key: key, filename: filename, byte_size: byte_size, checksum: checksum, content_type: content_type, record: record
|
|
end
|
|
|
|
def build_blob_after_unfurling(key: nil, data: "Hello world!", filename: "hello.txt", content_type: "text/plain", identify: true, record: nil)
|
|
ActiveStorage::Blob.build_after_unfurling key: key, io: StringIO.new(data), filename: filename, content_type: content_type, identify: identify, record: record
|
|
end
|
|
|
|
def directly_upload_file_blob(filename: "racecar.jpg", content_type: "image/jpeg", record: nil)
|
|
file = file_fixture(filename)
|
|
byte_size = file.size
|
|
checksum = Digest::MD5.file(file).base64digest
|
|
|
|
create_blob_before_direct_upload(filename: filename, byte_size: byte_size, checksum: checksum, content_type: content_type, record: record).tap do |blob|
|
|
service = ActiveStorage::Blob.service.try(:primary) || ActiveStorage::Blob.service
|
|
service.upload(blob.key, file.open)
|
|
end
|
|
end
|
|
|
|
def read_image(blob_or_variant)
|
|
MiniMagick::Image.open blob_or_variant.service.send(:path_for, blob_or_variant.key)
|
|
end
|
|
|
|
def extract_metadata_from(blob)
|
|
blob.tap(&:analyze).metadata
|
|
end
|
|
|
|
def fixture_file_upload(filename)
|
|
Rack::Test::UploadedFile.new file_fixture(filename).to_s
|
|
end
|
|
|
|
def with_service(service_name)
|
|
previous_service = ActiveStorage::Blob.service
|
|
ActiveStorage::Blob.service = service_name ? ActiveStorage::Blob.services.fetch(service_name) : nil
|
|
|
|
yield
|
|
ensure
|
|
ActiveStorage::Blob.service = previous_service
|
|
end
|
|
end
|
|
|
|
require "global_id"
|
|
GlobalID.app = "ActiveStorageExampleApp"
|
|
ActiveRecord::Base.include GlobalID::Identification
|
|
|
|
class User < ActiveRecord::Base
|
|
validates :name, presence: true
|
|
|
|
has_one_attached :avatar
|
|
has_one_attached :cover_photo, dependent: false, service: :local
|
|
has_one_attached :avatar_with_variants do |attachable|
|
|
attachable.variant :thumb, resize: "100x100"
|
|
end
|
|
|
|
has_many_attached :highlights
|
|
has_many_attached :vlogs, dependent: false, service: :local
|
|
has_many_attached :highlights_with_variants do |attachable|
|
|
attachable.variant :thumb, resize: "100x100"
|
|
end
|
|
|
|
accepts_nested_attributes_for :highlights_attachments, allow_destroy: true
|
|
end
|
|
|
|
class Group < ActiveRecord::Base
|
|
has_one_attached :avatar
|
|
has_many :users, autosave: true
|
|
|
|
accepts_nested_attributes_for :users
|
|
end
|
|
|
|
require_relative "../../tools/test_common"
|