Rails 5 + Shrine + 多态模型 + 漂亮的位置

Posted

技术标签:

【中文标题】Rails 5 + Shrine + 多态模型 + 漂亮的位置【英文标题】:Rails 5 + Shrine + Polymorphic model + Pretty Location 【发布时间】:2019-03-13 08:32:06 【问题描述】:

我正在使用 Shrine 直接上传到 S3,我正在尝试使用 pretty_location 插件在我的 S3 存储桶中设置位置。

我有一个文档模型具有file_datatext 属性并连接到 FileUploader:

class Document < ApplicationRecord
  belongs_to :documentable, polymorphic: true
  include FileUploader[:file]

  validates :file, presence: true
end

其他模型通过以下关注点与文档模型相关联:

module Documentable
  extend ActiveSupport::Concern

  included do
    has_one :document, as: :documentable, dependent: :destroy
    accepts_nested_attributes_for :document, allow_destroy: true
  end
end

这是我的文件上传器:

class FileUploader < Shrine
  Attacher.promote  |data| PromoteJob.perform_later(data) 
  Attacher.delete  |data| DeleteJob.perform_later(data) 

  plugin :upload_options, cache: acl: "public-read"
  plugin :upload_options, store: acl: "public-read"
  plugin :logging, logger: Rails.logger
  plugin :pretty_location
  plugin :processing
  plugin :delete_promoted
  plugin :recache
  plugin :restore_cached_data
  plugin :delete_raw
  plugin :validation_helpers

  def generate_location(io, context = )
    # do something depending on context[:record].documentable
  end
end

当通过客户端浏览器通过嵌套属性从用户的文件系统上传文件时,一切都按预期工作,我能够在我的 S3 存储桶中生成一个漂亮的位置。

但是,我有另一个模型,我正在尝试将一个 PDF 文件上传到 S3,该文件是在后端使用以下设置生成的。

class Invoice < ApplicationRecord
  has_one :documents, as: :documentable, dependent: :destroy
end 

Invoice 模型不使用关注点,因为我希望它通过 has_many 关联连接到多态文档。

class Api::V1::InvoicesController < Api::V1::BaseController
  def upload_pdf
    pdf = InvoicePdf.new(@invoice)
    attachment = pdf.render
    file = StringIO.new(attachment)
    file.class.class_eval  attr_accessor :original_filename, :content_type 
    file.original_filename = "invoice_#@invoice.reference.pdf"
    file.content_type = "application/pdf"
    @document = @invoice.documents.new(file: file)
    if @document.save
      render "documents/show.json", status: :created
    else
      render json:  errors: @document.errors , status: :unprocessable_entity
    end
  end
end

上传工作正常,我可以将 PDF 上传到我的 S3 存储桶,但我无法生成漂亮的位置,因为当我在 generate_location 方法中时,context[:record]documentable_typedocumentable_idnil

这是一个奇怪的行为,因为在 rails 控制台中,我可以通过运行 Invoice.last.documents.file.url 看到在上传完成后正确设置了关联(没有 pretty_location)。

我尝试过以不同的方式创建文档记录,尝试过使用同样适用于其他模型的 documentable 关注点,但结果始终相同,我已经没有想法了。

有人知道为什么 documentable_typedocumentable_id 没有被传递到 FileUploader 内的 context 对象中吗?

【问题讨论】:

【参考方案1】:

上述设置确实有效。我在generate_location FileUploader 方法中使用了一个断点,而 api 正在中断,因为该方法返回 nil。

修复该问题后,它第一次运行 documentable 仍然为零,但该方法将在 documentable 属性存在的情况下第二次运行。

def generate_location(io, context = )
  return "" unless context[:record].documentable
  path =  if context[:record].documentable_type == "SomeClass"
            # do something
          elsif context[:record].documentable_type == "OtherClass"
            # do something else
          else
            # do something else
          end
  return path
end

【讨论】:

以上是关于Rails 5 + Shrine + 多态模型 + 漂亮的位置的主要内容,如果未能解决你的问题,请参考以下文章

Rails 6 - Shrine - ImageProcessing - 获取原始上传文件

Rails 5 - 使用多态关联 - 渲染视图

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

Shrine Gem Ruby on Rails 无服务器图像处理程序,后台作业

具有多态模型的 Rails 范围

Rails:如何创建多态关系/友谊模型