将文件传递给活动作业/后台作业

时间:2017-10-12 08:38:42

标签: ruby-on-rails redis background-process sidekiq resque

我通过标准文件输入接收请求中的文件

def create
  file = params[:file]
  upload = Upload.create(file: file, filename: "img.png")
end

但是,对于大型上传,我希望在后台工作中执行此操作。 像Sidekiq或Resque这样的流行后台作业选项依赖于Redis来存储参数,因此我无法通过redis传递文件对象。

我可以使用Tempfile,但在某些平台上,例如Heroku,本地存储不可靠。

我有什么选择可以让它在#34;任何"平台?

3 个答案:

答案 0 :(得分:2)

我建议您直接上传到Amazon S3这样的服务,然后按照您认为适合后台工作的方式处理该文件。

当用户上传文件时,您可以确保它将安全地存储在S3中。您可以使用专用存储桶来禁止公共访问。然后,在后台任务中,您可以通过传递文件的S3 URI来处理上传,并让后台工作人员下载文件。

我不知道你的后台工作人员对该文件做了什么,但不用说再次下载它可能没有必要。它毕竟存储在某个地方。

我过去曾使用carrierwave-direct宝石成功。由于你提到了Heroku,他们有一个详细的guide用于将文件直接上传到S3。

答案 1 :(得分:1)

没有临时文件

听起来您想要加快图片上传速度或将其推送到后台。这是my suggestions from another post。如果这就是你要找的东西,也许他们会帮助你。

我发现这个问题的原因是因为我想保存一个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

答案 2 :(得分:0)

首先,您应该保存存储上的文件(本地或AWS S3)。 然后将 filepath或uuid 作为参数传递给后台作业。

我强烈建议避免在参数上传递Tempfile 。这会将对象存储在内存中,该对象可能会过时,从而导致过时的数据问题。