Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PictureThumb.storage_class #2435

Merged
merged 1 commit into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/models/alchemy/picture/url.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def uid
else
uid = PictureThumb::Uid.call(signature, variant)
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
PictureThumb.generator_class.call(variant, signature, uid)
PictureThumb::Create.call(variant, signature, uid)
end
uid
end
Expand Down
20 changes: 10 additions & 10 deletions app/models/alchemy/picture_thumb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module Alchemy
# different thumbnail store (ie. a remote file storage).
#
# config/initializers/alchemy.rb
# Alchemy::PictureThumb.generator_class = My::ThumbnailGenerator
# Alchemy::PictureThumb.storage_class = My::ThumbnailStore
#
class PictureThumb < BaseRecord
belongs_to :picture, class_name: "Alchemy::Picture"
Expand All @@ -16,18 +16,18 @@ class PictureThumb < BaseRecord
validates :uid, presence: true

class << self
# Thumbnail generator class
# Thumbnail storage class
#
# @see Alchemy::PictureThumb::Create
def generator_class
@_generator_class ||= Alchemy::PictureThumb::Create
# @see Alchemy::PictureThumb::FileStore
def storage_class
@_storage_class ||= Alchemy::PictureThumb::FileStore
end

# Set a thumbnail generator class
# Set a thumbnail storage class
#
# @see Alchemy::PictureThumb::Create
def generator_class=(klass)
@_generator_class = klass
# @see Alchemy::PictureThumb::FileStore
def storage_class=(klass)
@_storage_class = klass
end

# Upfront generation of picture thumbnails
Expand All @@ -49,7 +49,7 @@ def generate_thumbs!(picture)
next if thumb

uid = Alchemy::PictureThumb::Uid.call(signature, variant)
generator_class.call(variant, signature, uid)
Alchemy::PictureThumb::Create.call(variant, signature, uid)
end
end
end
Expand Down
25 changes: 7 additions & 18 deletions app/models/alchemy/picture_thumb/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

module Alchemy
class PictureThumb < BaseRecord
# Stores the render result of a Alchemy::PictureVariant
# in the configured Dragonfly datastore
# (Default: Dragonfly::FileDataStore)
# Creates a Alchemy::PictureThumb
#
# Stores the processes result of a Alchemy::PictureVariant
# in the configured +Alchemy::PictureThumb.storage_class+
# (Default: {Alchemy::PictureThumb::FileStore})
#
class Create
class << self
Expand All @@ -24,26 +26,13 @@ def call(variant, signature, uid)
thumb.uid = uid
end
begin
# process the image
image = variant.image
# store the processed image
image.to_file(server_path(uid)).close
rescue RuntimeError => e
Alchemy::PictureThumb.storage_class.call(variant, uid)
rescue StandardError => e
ErrorTracking.notification_handler.call(e)
# destroy the thumb if processing or storing fails
@thumb&.destroy
end
end

private

# Alchemys dragonfly datastore config seperates the storage path from the public server
# path for security reasons. The Dragonfly FileDataStorage does not support that,
# so we need to build the path on our own.
def server_path(uid)
dragonfly_app = ::Dragonfly.app(:alchemy_pictures)
"#{dragonfly_app.datastore.server_root}/#{uid}"
end
end
end
end
Expand Down
33 changes: 33 additions & 0 deletions app/models/alchemy/picture_thumb/file_store.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

module Alchemy
class PictureThumb < BaseRecord
# Stores the render result of a Alchemy::PictureVariant
# in the configured Dragonfly datastore
# (Default: Dragonfly::FileDataStore)
#
class FileStore
class << self
# @param [Alchemy::PictureVariant] variant the to be rendered image
# @param [String] uid The Unique Image Identifier the image is stored at
#
def call(variant, uid)
# process the image
image = variant.image
# store the processed image
image.to_file(server_path(uid)).close
end

private

# Alchemys dragonfly datastore config seperates the storage path from the public server
# path for security reasons. The Dragonfly FileDataStorage does not support that,
# so we need to build the path on our own.
def server_path(uid)
dragonfly_app = ::Dragonfly.app(:alchemy_pictures)
"#{dragonfly_app.datastore.server_root}/#{uid}"
end
end
end
end
end
27 changes: 27 additions & 0 deletions spec/models/alchemy/picture_thumb/file_store_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe Alchemy::PictureThumb::FileStore do
let(:image) { File.new(File.expand_path("../../../fixtures/image.png", __dir__)) }
let(:picture) { FactoryBot.create(:alchemy_picture, image_file: image) }
let!(:variant) { Alchemy::PictureVariant.new(picture, { size: "1x1" }) }
let(:uid_path) { "pictures/#{picture.id}/1234" }

let(:root_path) do
datastore = Dragonfly.app(:alchemy_pictures).datastore
datastore.server_root
end

subject(:store) do
Alchemy::PictureThumb::FileStore.call(variant, "/#{uid_path}/image.png")
end

before do
FileUtils.rm_rf("#{root_path}/#{uid_path}")
end

it "stores thumb on the disk" do
expect { store }.to change { Dir.glob("#{root_path}/#{uid_path}").length }.by(1)
end
end