Рельсы 5 + Храм + Полиморфная модель + Симпатичное расположение - PullRequest
0 голосов
/ 08 октября 2018

Я использую Shrine для прямой загрузки на S3, и я пытаюсь использовать плагин pretty_location, чтобы установить местоположение в моем контейнере S3.

У меня есть модель документа с file_dataтекстовый атрибут и подключен к 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

Это мой FileUploader:

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.

Однако у меня есть другая модель, в которойЯ пытаюсь загрузить на S3 файл PDF, сгенерированный в бэкэнде со следующей настройкой.

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_type и documentable_id nil.

Это странное поведение, так как в консоли rails я могуувидеть, что связь установлена ​​правильно после завершения загрузки (без pretty_location) с помощью команды Invoice.last.documents.file.url.

Я пытался создать запись документа различными способами, пытался использовать ту же самую проблему documentable, котораяработает для других моделей, но результат всегда тот же, и у меня закончились идеи.

Кто-нибудь знает, почему documentable_type и documentable_id не передаются в объект context внутриFileUploader?

1 Ответ

0 голосов
/ 08 октября 2018

Вышеуказанная настройка действительно работает.Я использовал точку останова в методе generate_location FileUploader, и API ломался, потому что этот метод возвращал ноль.

После исправления этого в первый раз при запуске 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
...