好的,所以我确实想出了如何做到这一点,我将在下面解释。我的直觉是使用两个不同的 CarrierWave 上传器类是正确的——一个类专门用于上传到 S3(使用 CarrierWave_Direct gem),第二个类仅用于图像处理(我已经在生产中使用的类)。我会尝试在下面发布相关代码,但如果有人有问题请告诉我。我不确定为什么我没有看到其他人使用这样的单独类,但它似乎对我有用。
我的图片上传器类app\uploaders\image_uploader.rb
使用carrierwave_direct gem:
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWaveDirect::Uploader
include ActiveModel::Conversion
extend ActiveModel::Naming
include CarrierWave::MimeTypes
process :set_content_type
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_white_list
%w(jpg jpeg gif png)
end
# Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility:
include Sprockets::Helpers::RailsHelper
include Sprockets::Helpers::IsolatedHelper
# Override the directory where uploaded files will be stored.
# CarrierWaveDirect::Uploader puts raw uploaded files in this directory on S3 as a first step
def store_dir
"unprocessed_uploads"
end
end
**注意在这个类中没有进行任何处理
我的图像处理类app\uploaders\image_processor.rb
(生产中已经存在的):
class ImageProcessor < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
include CarrierWave::MiniMagick
include CarrierWave::MimeTypes
process :set_content_type
# Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility:
include Sprockets::Helpers::RailsHelper
include Sprockets::Helpers::IsolatedHelper
# Choose what kind of storage to use for this uploader:
storage :fog
# 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}"
# "uploads/#{model.class.to_s.underscore}/path/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
def default_url
"logos/" + [version_name, "default.png"].compact.join('_')
end
# Process files fetched from S3 after they are uploaded:
def make_thumbnail(width, height)
# uses MiniMagick classes to get a square, centered thumbnail image
manipulate! do |img|
if img[:width] < img[:height]
remove = ((img[:height] - img[:width])/2).round
img.shave("0x#{remove}")
elsif img[:width] > img[:height]
remove = ((img[:width] - img[:height])/2).round
img.shave("#{remove}x0")
end
img.resize("#{width}x#{height}")
img
end
end
# Create different versions of your uploaded files:
# the process statement below isn't defined within a version block on purpose--this means the ORIGINAL uploaded photo is constrained to 1050 pics
process :resize_to_limit => [1050, 1050]
process :quality => 85 # this reduces filesize greatly and saves space
version :thumb do
process :make_thumbnail => [100, 100]
process :quality => 85 # this reduces filesize greatly and saves space
end
version :big_thumb do
process :make_thumbnail => [350, 350]
process :quality => 85 # this reduces filesize greatly and saves space
end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_white_list
%w(jpg jpeg gif png)
end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
def filename
if original_filename
if model && model.read_attribute(:image).present?
model.read_attribute(:image)
else
"#{secure_token}.#{file.extension}"
end
end
end
protected
def secure_token
var = :"@#{mounted_as}_secure_token"
model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid)
end
end
我的照片模型(总结):
class Photo < ActiveRecord::Base
mount_uploader :image, ImageProcessor
def save_and_process_image(options = {})
s3_unprocessed_image_url = self.image.asset_host + '/' + self.key
# this next line downloads the image from S3
# and this save line below will process the image and reupload to S3 according to ImageProcessor settings
self.remote_image_url = s3_unprocessed_image_url
save
end
end
我也有可用的照片控制器和查看代码,如果你想要它让我知道。基本上,我使用 ImageUploader 类将初始上传到 S3 到一个名为 unprocessed_uploads 的文件夹。然后 S3 用key
我传递给 ImageProcessor 类的 URL 中的一个字段进行响应——它附加到照片并处理缩略图和其他图像,然后将它们重新上传到我在 S3 上的上传文件夹。
这种分离意味着我在添加carrierwave_direct gem 时不需要更改我在S3 上的当前文件夹结构。希望这对其他人有帮助。如果您需要更多代码,请告诉我,我有点厌倦了打字:)
更新——添加更多代码:
照片控制器:
class PhotosController < ApplicationController
def index
@photos = @photos.sort_by(&:created_at)
@uploader = ImageUploader.new
@uploader.success_action_redirect = new_tank_photo_url(@tank)
respond_to do |format|
format.html # index.html.erb
format.json { render json: @photos }
end
end
def create
respond_to do |format|
if @photo.save_and_process_image
format.html { redirect_to tank_photos_path(@tank), notice: 'Photo uploaded successfully and is being processed...' }
format.json { render json: @photo, status: :created, location: @photo }
else
format.html { render :new }
format.json { render json: @photo.errors, status: :unprocessable_entity }
end
end
end
照片索引视图,带有上传按钮的表单:
<%= direct_upload_form_for @uploader, :html => {:class => "form-inline"} do |f| %>
<%= f.file_field :image %>
<%= f.submit "Upload", :class => "btn btn-primary btn-medium" %>
<% end %>
因此,添加了上述视图/控制器代码后,这里是所采取步骤的摘要。ImageUploader
请注意类和类之间的区别ImageProcessor
:
- 在我的照片控制器中,我创建了属于 ImageUploader 类的 @uploader 变量——这意味着在使用 @uploader 的索引/视图表单中提交的图像会将图像上传到“临时”文件夹——因为它使用 ImageUploader 类然后在上传此图像时(尚未)不进行任何处理。
- 当用户单击表单上的“上传”按钮时,会调用照片>>创建操作。此操作调用@photo.save_and_process_image - 查看模型以查看此方法实际上从 S3 的“临时”文件夹中获取最近上传的图像,对其进行处理,然后将处理后的图像重新上传到其最终目的地。这一切都是可能的,因为我的 Photo 模型链接到ImageProcessor类,该类进行处理/上传。它没有链接到单独的 ImageUploader 类。
希望这有助于解释我正在发生的事情