活动存储 - 多项服务 - 直接上传未按预期工作
active storage - multiple services - direct upload not working as expected
我在 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
我对一些文件使用亚马逊服务,我想对其他文件使用 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
在railsapplication.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 %>
现在我知道(或者我想我知道)在 rails 中使用 active_storage
时直接上传是如何工作的。
一些 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
。我的应用程序执行前者。
来自 OP 的更新:
I ended up re-opening DirectUploadsController (and also adding an option to the form file_field to pass a custom direct_upload_url It works nicely although I don't like that I had to mingle with internals soo much. I've checked active_storage gem and it seems that one would have to just add this feature cause with current implementation there is no workaround. – beniutek
这是一个已知问题。此 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
不使用 direct_upload 选项,而是手动设置数据属性 data-direct-upload-url
。例如:
<%= form.file_field :file, multipart: true,
"data-direct-upload-url" => rails_direct_uploads_url(service: "unsafe_files") %>
我在 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
我对一些文件使用亚马逊服务,我想对其他文件使用 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
在railsapplication.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 %>
现在我知道(或者我想我知道)在 rails 中使用 active_storage
时直接上传是如何工作的。
一些 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
。我的应用程序执行前者。
来自 OP 的更新:
I ended up re-opening DirectUploadsController (and also adding an option to the form file_field to pass a custom direct_upload_url It works nicely although I don't like that I had to mingle with internals soo much. I've checked active_storage gem and it seems that one would have to just add this feature cause with current implementation there is no workaround. – beniutek
这是一个已知问题。此 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
不使用 direct_upload 选项,而是手动设置数据属性 data-direct-upload-url
。例如:
<%= form.file_field :file, multipart: true,
"data-direct-upload-url" => rails_direct_uploads_url(service: "unsafe_files") %>