diff --git a/app/models/spree/preferences/file_configuration.rb b/app/models/spree/preferences/file_configuration.rb index 7015e60296..421484993f 100644 --- a/app/models/spree/preferences/file_configuration.rb +++ b/app/models/spree/preferences/file_configuration.rb @@ -5,6 +5,10 @@ module Spree class FileConfiguration < Configuration def self.preference(name, type, *args) if type == :file + # Active Storage blob id: + super "#{name}_blob_id", :integer, *args + + # Paperclip attachment attributes: super "#{name}_file_name", :string, *args super "#{name}_content_type", :string, *args super "#{name}_file_size", :integer, *args @@ -17,7 +21,12 @@ module Spree def get_preference(key) if !has_preference?(key) && has_attachment?(key) + # Call Paperclip's attachment method: public_send key + elsif key.ends_with?("_blob") + # Find referenced Active Storage blob: + blob_id = super("#{key}_id") + ActiveStorage::Blob.find_by(id: blob_id) else super key end @@ -37,7 +46,11 @@ module Spree # errors if respond_to? isn't correct, so we override it here. def respond_to?(method, include_all = false) name = method.to_s.delete('=') - super(self.class.preference_getter_method(name), include_all) || super(method, include_all) + reference_name = "#{name}_id" + + super(self.class.preference_getter_method(name), include_all) || + super(reference_name, include_all) || + super(method, include_all) end def has_attachment?(name) diff --git a/lib/tasks/from_paperclip_to_active_storage.rake b/lib/tasks/from_paperclip_to_active_storage.rake index 1d59f65f12..8859c7bed4 100644 --- a/lib/tasks/from_paperclip_to_active_storage.rake +++ b/lib/tasks/from_paperclip_to_active_storage.rake @@ -14,6 +14,25 @@ namespace :from_paperclip_to_active_storage do end end + # We have a special class called ContentConfiguration which is not a model + # and therfore can't use the normal Active Storage magic. + # + # It uses `Spree::Preference`s to store all the Paperclip attributes. These + # files are stored locally and we can replace them with preferences pointing + # to an Active Storage blob. + desc "Associate ContentConfig to ActiveStorage blobs" + task copy_content_config: :environment do + [ + :logo, + :logo_mobile, + :logo_mobile_svg, + :home_hero, + :footer_logo, + ].each do |name| + migrate_content_config_file(name) + end + end + def migrate_model(model) duplicated_attachment_names(model).each do |name| migrate_attachment(model, name) @@ -71,6 +90,23 @@ namespace :from_paperclip_to_active_storage do ) end + def migrate_content_config_file(name) + paperclip = ContentConfig.public_send(name) + + return if ContentConfig.public_send("#{name}_blob_id") + return if paperclip.path.blank? || !paperclip.exists? + + blob = ActiveStorage::Blob.create_and_upload!( + io: File.open(paperclip.path), + filename: paperclip.original_filename, + content_type: paperclip.content_type, + identify: false, + ) + + ContentConfig.public_send("#{name}_blob_id=", blob.id) + puts "Copied #{name}" + end + def duplicated_attachment_names(model) paperclip_attachments = model.attachment_definitions.keys.map(&:to_s) active_storage_attachments = model.attachment_reflections.keys diff --git a/spec/lib/tasks/from_paperclip_to_active_storage_rake_spec.rb b/spec/lib/tasks/from_paperclip_to_active_storage_rake_spec.rb index 8f3641ba16..e13cfc2a18 100644 --- a/spec/lib/tasks/from_paperclip_to_active_storage_rake_spec.rb +++ b/spec/lib/tasks/from_paperclip_to_active_storage_rake_spec.rb @@ -31,7 +31,7 @@ describe "from_paperclip_to_active_storage.rake" do end describe ":migrate" do - it "creates Active Storage records for existing images on disk" do |example| + it "creates Active Storage records for existing images on disk" do image = Spree::Image.create!(attachment: file) image.attachment_attachment.delete image.attachment_blob.delete @@ -43,7 +43,7 @@ describe "from_paperclip_to_active_storage.rake" do }.to(true) end - it "creates Active Storage records for existing images on disk" do |example| + it "creates Active Storage records for images on AWS S3" do attachment_definition = Spree::Image.attachment_definitions[:attachment] allow(Spree::Image).to receive(:attachment_definitions).and_return( attachment: attachment_definition.merge(s3_config) @@ -74,6 +74,35 @@ describe "from_paperclip_to_active_storage.rake" do end end + describe ":copy_content_config" do + it "doesn't copy default images" do + run_task "from_paperclip_to_active_storage:copy_content_config" + + expect(ContentConfig.logo_blob).to eq nil + end + + it "copies uploaded images" do + ContentConfig.logo = file + ContentConfig.logo.save + + run_task "from_paperclip_to_active_storage:copy_content_config" + + expect(ContentConfig.logo_blob).to be_a ActiveStorage::Blob + end + + it "doesn't copy twice" do + ContentConfig.logo = file + ContentConfig.logo.save + + expect { + run_task "from_paperclip_to_active_storage:copy_content_config" + run_task "from_paperclip_to_active_storage:copy_content_config" + }.to change { + ActiveStorage::Blob.count + }.by(1) + end + end + def run_task(name) Rake::Task[name].reenable Rake.application.invoke_task(name)