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.
This commit is contained in:
Maikel Linke
2022-03-17 14:54:38 +11:00
parent 95cb6e93e7
commit ec64e5c8f7
3 changed files with 57 additions and 0 deletions

View File

@@ -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

View File

@@ -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"] %>

View File

@@ -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