I’m not sure if it’s a bug or not, but sure seems like undesirable behavior.
Here’s my use-case:
- I’m uploading an image
- I generate a placeholder for the image and store it as metadata
- I unpack the placeholder to model using
metadata_attributes
However, the metadata gets calculated before we’ve run the validations, which is critical in my case — it runs an exception if the data is not valid.
Here’s a script to reproduce it:
# frozen_string_literal: true
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'sequel'
gem 'shrine'
gem 'sqlite3'
gem 'image_processing'
gem 'mini_magick'
end
require 'sequel'
require 'mini_magick'
require 'image_processing'
require 'shrine'
require 'shrine/storage/memory'
Shrine.storages = {
cache: Shrine::Storage::Memory.new,
store: Shrine::Storage::Memory.new
}
Shrine.plugin :sequel
class MyUploader < Shrine
plugin :add_metadata
plugin :metadata_attributes, placeholder: :placeholder
plugin :validation_helpers
Attacher.validate do
if validate_mime_type_inclusion(%w[image/jpg image/jpeg image/png])
validate_max_width 20_000
validate_max_height 20_000
end
end
add_metadata :placeholder, skip_nil: true do |io, action:, **_context|
placeholder = ::ImageProcessing::MiniMagick
.source(MiniMagick::Image.read(io))
.loader(page: 0)
.resize_to_fill(4, 4)
.convert('png')
Base64.strict_encode64(placeholder)
end
end
File.write('image.html', <<~HTML)
<!doctype html />
<html>
<head></head>
<body></body>
</html>
HTML
DB = Sequel.sqlite # SQLite memory database
DB.create_table :posts do
primary_key :id
String :image_data
String :image_placeholder
end
class Post < Sequel::Model
include MyUploader::Attachment(:image)
end
post = Post.create(image: File.open('image.html'))
It’ll fail because HTML is not an image. I’ve tried changing order of the plugins to no avail.
There’s another problem: I’m using derivatives
plugin, which won’t let me compute metadata for original
unless action
is cache
. Which runs before validations
.
If I compute the same metadata on a derivative, I won’t be able to use it with extract_metadata
, as I understand from docs and my feeble attempts.
So here’s that.
Is it a bug that metadata gets calculated before validations? How do we solve it?