Carrierwave背景和Heroku - tmp问题

时间:2015-03-19 20:44:00

标签: ruby-on-rails heroku carrierwave delayed-job tmp

我正在将图片上传到我的图片模型。我正在使用Carrierwave,Carrierwave-Backgrounder,Carrierwave-FTP for SFTP和DelayedJob。

目标是通过SFTP在后台处理和存储图像。我的方法在我的开发环境中运行良好,但在Heroku上生产失败。

我理解这是因为Heroku的tmp目录在创建操作后被擦除了,但我正在寻找解决方法。

是否可以使用S3 / Fog存储tmp文件?然后使用Carrierwavebackgrounder从那里访问它们。 或者有更好的方法吗?

者:

# encoding: utf-8

class ImageUploader < CarrierWave::Uploader::Base

  def cache_dir
    "#{Rails.root}/tmp/uploads"
  end

  include ::CarrierWave::Backgrounder::Delay
  include CarrierWave::MiniMagick

  storage :sftp

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    # "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
    "/"
  end

  def rotate(degree)
    manipulate! do |img|
      img.rotate(degree)
      img
    end
  end

  version :tiny, :if => :initial? do
    process :resize_to_fit => [75, 75]
    def full_filename(for_file = model.image.file)
      model.product_code.to_s + "-0.jpg"
    end
  end

  version :small, :if => :initial? do
    process :resize_to_fit => [200, 200]
    def full_filename(for_file = model.image.file)
      model.product_code.to_s + "-1.jpg"
    end
  end

  version :medium, :if => :initial? do
    process :resize_to_fit => [500, 500]
    def full_filename(for_file = model.image.file)
      model.product_code.to_s + "-2T.jpg"
    end
  end

  version :large, :if => :initial? do
    process :resize_to_fit => [1000, 1000]
    def full_filename(for_file = model.image.file)
      model.product_code.to_s + "-2.jpg"
    end
  end

  version :medium_alt, :if => :initial? do
    process :resize_to_fit => [100, 50]
    def full_filename(for_file = model.image.file)
      model.product_code.to_s + "-2S.jpg"
    end
  end

  version :medium_additional, :if => :additional? do
    process :resize_to_fit => [500, 500]
    def full_filename(for_file = model.image.file)
      model.product_code.to_s + "-#{model.version_number}" + "T.jpg"
    end
  end

  version :large_additional, :if => :additional? do
    process :resize_to_fit => [1000, 1000]
    def full_filename(for_file = model.image.file)
      model.product_code.to_s + "-#{model.version_number}" + ".jpg"
    end
  end

  version :medium_alt_additional, :if => :additional? do
    process :resize_to_fit => [100, 50]
    def full_filename(for_file = model.image.file)
      model.product_code.to_s + "-#{model.version_number}" + "S.jpg"
    end
  end

  version :ebay_initial, :if => :initial? do
    process :resize_to_fit => [1600, 1600]
    def full_filename(for_file = model.image.file)
      model.product_code.to_s + "-ebay.jpg"
    end
  end

  version :ebay_additional, :if => :additional? do
    process :resize_to_fit => [1600, 1600]
    def full_filename(for_file = model.image.file)
      model.product_code.to_s + "-#{model.version_number}" + "-ebay.jpg"
    end
  end

  version :display_initial, :if => :initial? do
    process :resize_to_fit => [200, 1000]
    def full_filename(for_file = model.image.file)
      model.product_code.to_s + "-display.jpg"
    end
  end

  version :display_additional, :if => :additional? do
    process :resize_to_fit => [200, 1000]
    def full_filename(for_file = model.image.file)
      model.product_code.to_s + "-#{model.version_number}" + "-display.jpg"
    end
  end

  protected

  def initial?(new_file)
    original_filename.to_i == 0
  end

  def additional?(new_file)
    original_filename.to_i > 0
  end

  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  # Currently inactive.
  # def extension_white_list
  #   %w(jpg jpeg)
  # end

end

Picture.rb:

class Picture < ActiveRecord::Base

  mount_uploader :image, ImageUploader

  store_in_background :image

  belongs_to :item
end

控制器上传:

def import_pictures(pictures, item)
    pictures['image'].each do |a|
      if a.original_filename.downcase.include?('.jpg') || a.original_filename.downcase.include?('.jpeg')
        count = @item.pictures.count
        photo_number = count + 2
        a.original_filename = count.to_s
        @picture = @item.pictures.create(:image => a, :item_id => item.id, :product_code => item.product_code, :version_number => photo_number)
      else
        flash[:error] = "Only .jpg and .jpeg files are allowed. Try again."
        redirect_to edit_item_path(@item)
      end
    end
  end

图片架构:

create_table "pictures", force: true do |t|
    t.integer  "item_id"
    t.string   "image"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "product_code"
    t.integer  "version_number"
    t.string   "image_tmp"
  end

Heroku Logs:

2015-03-19T20:27:56.804863+00:00 app[worker.1]: 2015-03-19T20:27:56+0000: [Worker(host:f84dfd71-bd05-4a44-ac83-1d1818d0bfe3 pid:3)] Job CarrierWave::Workers::StoreAsset (id=36) FAILED (5 prior attempts) with Errno::ENOENT: No such file or directory - /app/tmp/uploads/1426795849-9-9664/3

1 个答案:

答案 0 :(得分:0)

目前您无法在heroku上使用store_in_background。来自README

# Heroku may deploy workers on separate servers from where your dyno cached the files.
#
# IMPORTANT: Only use this method if you have full control over your tmp storage directory.

所以你必须直接存储(没有后台程序)并且 process_in_background 可以延迟。