在使用 Shrine 和 Rails 加密之前为图像文件设置 mime 类型

setting mime type for image files before they are encrypted with Shrine and Rails

我的应用程序加密并上传某些文件,然后让管理员可以看到它们。为了实现后一种功能,my encryption gem's documentation 建议使用如下所示的控制器操作:

def show
 user = User.find(params[:id])
 lockbox = Lockbox.new(key: Lockbox.attribute_key(table: "id_docs", attribute: "image"))
 send_data lockbox.decrypt(user.id_docs.image.read), type: user.id_docs.image.mime_type, disposition: 'inline'
end

我想要流式传输文件,但浏览器不知道如何解释它,而是下载。文件在上传前已加密,Shrine 将这些文件的 mime 类型设置为 application/octet-stream

我的创建操作如下所示:

def create
 image = params.require(:id_doc).fetch(:image)
 respond_to do |format|
  if Shrine.mime_type(image) == 'image/jpeg'
   lockbox = Lockbox.new(key: Lockbox.attribute_key(table: "id_docs", attribute: "image"))
   encrypted_image = lockbox.encrypt_io(image)
   @id_doc = IdDoc.create(user_id: current_user.id, image: encrypted_image)
   @id_doc.save
   format.html { redirect_to root_path }
  else
   format.html { redirect_to current_path }
  end
 end
end

如果我加密文件,mime类型保存为image/pngimage/jpeg,这就是我想要的。

IdDoc.rb 有一个名为 :image 的虚拟属性,它映射到数据库中的一个 image_data 字段:

class IdDoc < ApplicationRecord
 belongs_to :user
 validates_presence_of :image
 include IdDocUploader::Attachment(:image)
end

schema.rb

create_table "id_docs", force: :cascade do |t|
 t.bigint "user_id"
 t.text "image_data"
end

保存到image_data的数据保存为json格式:{\"id\":\"iddoc/1/image/2de32e77f306f0e95aed24623e930683.png\",\"storage\":\"store\",\"metadata\":{\"filename\":\"Screen Shot 2020-10-31 at 7.24.08 AM.png\",\"size\":47364,\"mime_type\":\"application/octet-stream\"}}

如何在文件创建之前更改 mime_type 的值?有没有什么办法可以用 Shrine 做到这一点,或者我应该超级 hacky 并直接解析 json?

简单地说:我认为你并没有完全按照 Shrine 的意图来做这件事,有多种方法可以解决这个问题。我将对它们进行排名(在我看来,基于 complexity/appropriateness)最好到最差:

  • 加密 could/should 被视为 Shrine processing/derivatives 概念的一部分。所以你想在那里执行处理并相应地设置元数据。 Shrine 作者本人在此处的线程中概述了处理原始文件的解决方案:https://discourse.shrinerb.com/t/keep-original-file-after-processing/50.
  • 您可以手动覆盖元数据:https://shrinerb.com/docs/metadata#controlling-extraction。这可能意味着不使用基于属性的分配,而是直接调用附加器(见下文)。
  • 您可以定义自己的 MIME 类型确定逻辑,如下所示:https://shrinerb.com/docs/plugins/determine_mime_type
  • 您已经在使用 Shrine.mime_type。使用从中获得的值并将其存储在 id_docs 模型的单独数据库列 mime_type 中,然后在从数据库中读取时使用它。请注意,这可能隐含地意味着此列中的值与您从文件元数据的 MIME 类型中获得的值不同步。

直接使用附件:

mime_type = Shrine.mime_type(image)

# ...

@id_doc = IdDoc.create(user_id: current_user.id) do |id_doc|
  id_doc.image_attacher.model_assign(encrypted_image, metadata: { mime_type: mime_type })
end