From ec64e5c8f729d76389910bca78c0bb4ba3eed30e Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 17 Mar 2022 14:54:38 +1100 Subject: [PATCH] Store images with Active Storage as well While we migrate from Paperclip to Active Storage, we need to use both at the same time to avoid any downtime or lost images. Once the migration is complete, we want to use the same name for attachment as before. Using Paperclip and Active Storage at the same time creates a name conflict on a couple of methods. I'm using alias_method as a temporary solution to access Active Storage methods. We will remove that after the migration. I declare Paperclip afterwards so that we have those methods declarations for backwards compatibility now. --- app/models/spree/image.rb | 23 +++++++++++++++++++++++ config/storage.yml | 7 +++++++ spec/models/spree/image_spec.rb | 27 +++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/app/models/spree/image.rb b/app/models/spree/image.rb index e508395729..3d835de7b2 100644 --- a/app/models/spree/image.rb +++ b/app/models/spree/image.rb @@ -7,6 +7,17 @@ module Spree validates_attachment_presence :attachment validate :no_attachment_errors + # Active Storage declaration + has_one_attached :attachment + + # Backup Active Storage methods before they get overridden by Paperclip. + alias_method :active_storage_attachment, :attachment + alias_method :active_storage_attachment=, :attachment= + + # Paperclip declaration + # + # This will define the `name` and `name=` methods as well. + # # This is where the styles are used in the app: # - mini: used in the BackOffice: Bulk Product Edit page and Order Cycle edit page # - small: used in the FrontOffice: Product List page @@ -21,6 +32,18 @@ module Spree path: ':rails_root/public/spree/products/:id/:style/:basename.:extension', convert_options: { all: '-strip -auto-orient -colorspace sRGB' } + after_post_process do + if attachment.errors.blank? + attachable = { + io: File.open(local_filename_of_original), + filename: attachment_file_name, + content_type: attachment_content_type, + identify: false, + } + self.active_storage_attachment = attachable + end + end + # save the w,h of the original image (from which others can be calculated) # we need to look at the write-queue for images which have not been saved yet after_post_process :find_dimensions diff --git a/config/storage.yml b/config/storage.yml index fbac2cd79c..255c8298d9 100644 --- a/config/storage.yml +++ b/config/storage.yml @@ -6,6 +6,13 @@ test: service: Disk root: <%= Rails.root.join("tmp/storage") %> +test_amazon: + service: S3 + access_key_id: "A...A" + secret_access_key: "H...H" + bucket: "ofn" + region: "us-east-1" + amazon: service: S3 access_key_id: <%= ENV["S3_ACCESS_KEY"] %> diff --git a/spec/models/spree/image_spec.rb b/spec/models/spree/image_spec.rb index eba817048b..06de9c955b 100644 --- a/spec/models/spree/image_spec.rb +++ b/spec/models/spree/image_spec.rb @@ -21,6 +21,18 @@ module Spree expect(attachment.file?).to eq true expect(attachment.url).to match %r"^/spree/products/[0-9]+/product/logo-black\.png\?[0-9]+$" end + + it "duplicates the image with Active Storage" do + image = Spree::Image.create!( + attachment: file, + viewable: product.master, + ) + + attachment = image.active_storage_attachment + url = Rails.application.routes.url_helpers.url_for(attachment) + + expect(url).to match %r|^http://test\.host/rails/active_storage/blobs/redirect/[[:alnum:]-]+/logo-black\.png$| + end end describe "using AWS S3" do @@ -47,9 +59,12 @@ module Spree allow(Spree::Image).to receive(:attachment_definitions).and_return( attachment: attachment_definition.merge(s3_config) ) + allow(Rails.application.config.active_storage). + to receive(:service).and_return(:test_amazon) end it "saves a new image when none is present" do + # Paperclip requests upload_pattern = %r"^https://ofn.s3.amazonaws.com/[0-9]+/(original|mini|small|product|large)/logo-black.png$" download_pattern = %r"^https://ofn.s3.amazonaws.com/[0-9]+/product/logo-black.png$" public_url_pattern = %r"^https://ofn.s3.us-east-1.amazonaws.com/[0-9]+/product/logo-black.png\?[0-9]+$" @@ -57,15 +72,27 @@ module Spree stub_request(:put, upload_pattern).to_return(status: 200, body: "", headers: {}) stub_request(:head, download_pattern).to_return(status: 200, body: "", headers: {}) + # Active Storage requests + as_upload_pattern = %r"^https://ofn.s3.amazonaws.com/[[:alnum:]]+$" + + stub_request(:put, as_upload_pattern).to_return(status: 200, body: "", headers: {}) + image = Spree::Image.create!( attachment: file, viewable: product.master, ) + # Paperclip attachment = image.attachment expect(attachment.exists?).to eq true expect(attachment.file?).to eq true expect(attachment.url).to match public_url_pattern + + # Active Storage + attachment = image.active_storage_attachment + expect(attachment).to be_attached + expect(Rails.application.routes.url_helpers.url_for(attachment)). + to match %r"^http://test\.host/rails/active_storage/blobs/redirect/[[:alnum:]-]+/logo-black\.png" end end end