【问题标题】:active storage - multiple services - direct upload not working as expected活动存储 - 多种服务 - 直接上传无法按预期工作
【发布时间】:2021-10-29 12:50:29
【问题描述】:

我在storage.yml 中定义了两个服务

amazon:
  service: S3
  bucket: bucket1
  region: eu-central-1
  access_key_id: 321
  secret_access_key: 321

unsafe_files:
  service: S3
  bucket: unsafe-files
  region: eu-central-1
  access_key_id: 123
  secret_access_key: 123

我对一些文件使用 amazon 服务,而我想对其他文件使用 unsafe_files 服务,这样我就可以将它们放入另一个 s3 存储桶中。

使用unsafe_files 服务的模型看起来像这样(非常简单):

class Customer < ActiveRecord::Base
  belongs_to :customer_image
end
class CustomerImage < Image
  has_one_attached :file, service: Rails.configuration.settings[:unsafe_files_service]
end

Rails.configuration.settings[:unsafe_files_service] 只是unsafe_files

在 rails application.rb 我正在设置

config.active_storage.service = :amazon 以便默认使用storage.yml 中定义的amazon 服务

现在我想用form_with直接上传文件,也很简单:

<%= form_with model: [@customer, CustomerImage.new] do |form| %>
  <%=
    form.file_field :file,
                    accept: 'image/jpeg',
                    direct_upload: true,
                    multipart: true
  %>
  <%= form.submit "submit" %>
<% end %>

现在我知道(或者我想我知道)在使用 active_storage 时,直接上传在 rails 的底层是如何工作的。 一些javascript监听表单提交事件,首先将file_field中的内容发送到DirectUploadsController,后者检查图像,生成直接上传url,然后我们直接将文件上传到指定的服务。都在这里:https://github.com/rails/rails/blob/6ecf1065da57360bdc9f1d85e2c2d9314dcb79e0/activestorage/app/controllers/active_storage/direct_uploads_controller.rb#L14

服务以文件密钥或 ID 响应。 之后表单提交继续,我们保存我们收到的id和文件之间的关系。

但是当我们点击 DirectUploadsController 并创建 blob 时,它会获得默认的 service_name(请参阅:https://github.com/rails/rails/blob/6ecf1065da57360bdc9f1d85e2c2d9314dcb79e0/activestorage/app/models/active_storage/blob.rb#L115

长话短说,当使用直接上传时,我无法选择服务,我必须依赖 Rails 默认服务。

有解决办法吗?或者我错过了什么?

【问题讨论】:

  • 如果你想自己打电话给create_before_direct_upload!(这样你就可以指定service_name),那么我认为你必须以某种方式覆盖DirectUploadsController。您可以编写自己的控制器,或者(高级)尝试重新打开并修补 DirectUploadsController。我的应用是前者。
  • 我最终重新打开了DirectUploadsController(并在file_field 表单中添加了一个选项以传递自定义direct_upload_url 虽然我不喜欢这样我不得不打成一片,但效果很好内部结构太多了。我检查了active_storage gem,似乎必须添加此功能,因为当前实现没有解决方法。
  • 很高兴你能成功。代替其他(更好的)答案,我会将我的评论转换为答案,希望它能够更好地出现在搜索中。
  • 我已经准备了一个带有粗略解决方案的要点。万一有人想看看我选择如何解决它。确切的代码可能会更好,但这是我采用的方法,它现在似乎对我们有用(尽管我们必须更改它,因为我已经看到主分支上的 fomr 标签助手正在更改)-> @987654323 @

标签: ruby-on-rails ruby ruby-on-rails-6 rails-activestorage


【解决方案1】:

如果您想自己调用create_before_direct_upload!(以便您可以指定service_name),那么我认为您必须以某种方式覆盖DirectUploadsController。您可以编写自己的控制器,或者(高级)尝试重新打开并修补 DirectUploadsController。我的应用是前者。

来自 OP 的更新:

我最终重新打开了 DirectUploadsController(并且还在表单 file_field 中添加了一个选项以传递自定义的 direct_upload_url 它工作得很好,虽然我不喜欢我不得不与内部组件打成一片。我已经检查过 active_storage gem并且似乎必须添加此功能,因为当前的实现没有解决方法。- beniutek

【讨论】:

  • 目前,这就是我解决问题的方式,因此接受了答案。希望他们将来会使其更加灵活
【解决方案2】:

这是一个已知问题。此PR 是针对该问题的,但由于另一个主题而被撤消。

我解决此问题的方法是覆盖 DirectUploadsController 中的 blob_args 方法。

# app/overrides/direct_uploads_controller_override.rb
ActiveStorage::DirectUploadsController.class_eval do
  alias_method :old_blob_args, :blob_args
  def blob_args
    old_blob_args.merge(service_name: params[:service])
  end
end

加载覆盖:

# config/application.rb
# ...
overrides = "#{Rails.root}/app/overrides"
Rails.autoloaders.main.ignore(overrides)

config.to_prepare do
  Dir.glob("#{overrides}/**/*_override.rb").each do |override|
    load override
  end
end

手动设置数据属性data-direct-upload-url,而不是使用direct_upload 选项。例如:

<%= form.file_field :file, multipart: true, 
    "data-direct-upload-url" => rails_direct_uploads_url(service: "unsafe_files") %>

【讨论】:

    猜你喜欢
    • 2013-08-18
    • 1970-01-01
    • 2019-06-20
    • 1970-01-01
    • 1970-01-01
    • 2020-03-29
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    相关资源
    最近更新 更多