我通过标准文件输入在请求参数中接收
文件def create
file = params[:file]
upload = Upload.create(file: file, filename: "img.png")
end
但是,对于大型上传,我想在后台作业中执行此操作。流行的后台作业选项(如 Sidekiq 或 Resque)依赖于 Redis 来存储参数,所以我不能只通过 redis 传递文件对象。
我可以使用Tempfile
,但是在某些平台上,例如Heroku,本地存储并不可靠。
我有什么选择可以使其在"任何"平台上可靠?
我建议直接上传到 Amazon S3 等服务,然后根据需要在后台作业中处理文件。
当用户上传文件时,您可以放心,它将安全地存储在 S3 中。您可以使用私有存储桶来禁止公有访问。然后,在后台任务中,您可以通过传递文件的 S3 URI 来处理上传,并让后台辅助角色下载文件。
我不知道您的后台工作人员如何处理该文件,但不用说,可能不需要再次下载它。毕竟它存储在某个地方。
我过去曾成功地使用过载波直接宝石。由于您提到了 Heroku,因此他们提供了将文件直接上传到 S3 的详细指南。
无临时文件
听起来您想加快图像上传速度或将其推送到后台。这是我在另一篇文章中的建议。如果这就是你要找的,也许他们会帮助你。
我发现这个问题的原因是因为我想保存一个 CSV 文件,并将我的后台作业添加到包含该文件中信息的数据库中。
我有一个解决方案。
因为你的问题有点不清楚,我懒得发布我自己的问题并回答我自己的问题,我就在这里发布答案。 哈哈
就像其他家伙说的那样,将文件保存在某个云存储服务上。对于亚马逊,您需要:
# Gemfile
gem 'aws-sdk', '~> 2.0' # for storing images on AWS S3
gem 'paperclip', '~> 5.0.0' # image processor if you want to use images
你也需要这个。在production.rb
中使用相同的代码但不同的存储桶名称
# config/environments/development.rb
Rails.application.configure do
config.paperclip_defaults = {
storage: :s3,
s3_host_name: 's3-us-west-2.amazonaws.com',
s3_credentials: {
bucket: 'my-bucket-development',
s3_region: 'us-west-2',
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
}
}
end
您还需要迁移
# db/migrate/20000000000000_create_files.rb
class CreateFiles < ActiveRecord::Migration[5.0]
def change
create_table :files do |t|
t.attachment :import_file
end
end
end
和一个模型
class Company < ApplicationRecord
after_save :start_file_import
has_attached_file :import_file, default_url: '/missing.png'
validates_attachment_content_type :import_file, content_type: %r{Atext/.*Z}
def start_file_import
return unless import_file_updated_at_changed?
FileImportJob.perform_later id
end
end
和一份工作
class FileImportJob < ApplicationJob
queue_as :default
def perform(file_id)
file = File.find file_id
filepath = file.import_file.url
# fetch file
response = HTTParty.get filepath
# we only need the contents of the response
csv_text = response.body
# use the csv gem to create csv table
csv = CSV.parse csv_text, headers: true
p "csv class: #{csv.class}" # => "csv class: CSV::Table"
# loop through each table row and do something with the data
csv.each_with_index do |row, index|
if index == 0
p "row class: #{row.class}" # => "row class: CSV::Row"
p row.to_hash # hash of all the keys and values from the csv file
end
end
end
end
在控制器中
def create
@file.create file_params
end
def file_params
params.require(:file).permit(:import_file)
end
首先,您应该将文件保存在存储(本地或 AWS S3)上。然后将文件路径或 uuid 作为参数传递给后台作业。
我强烈建议避免在参数上传递临时文件。这会将对象存储在内存中,这些对象可能会过时,从而导致过时的数据问题。