ruby-on-rails - CarrierWave_Direct gem : Keep current directory structure on S3

标签 ruby-on-rails image amazon-s3 carrierwave

所以我有一个网站已经在生产中使用carrierwave gem,图像存储在亚马逊s3上。我的上传者使用 store_dir方法来指定要放入处理过的图像的特定结构。

好吧,现在在我的开发环境中,我添加了carrierwave_direct gem 以开始直接上传到 S3。问题是这个 gem 完全覆盖了我的上传器中的 store_dir 和文件名默认值。我无法实时推送我完全正常工作的上传器,因为我所有的旧图片链接都将被破坏。

我的理解是 CWdirect gem 会将原始图像文件上传到 S3 上的“临时”目录,然后 S3 做出响应并为您提供 key变量,以便您可以获取此文件并按照您认为合适的方式处理它。那么,我应该在carrierwave中使用一个完全独立的图像上传类来处理图像并将它们放在正确的文件夹中吗?这意味着我将有一个专门用于carrierwave_direct 的上传器,可以上传这个 gem 似乎想要上传到的任何地方;并且我将使用另一个链接到我的真实模型的uploader.rb 类来保留我当前的store_dir 和文件名结构?

无论如何,我的基本问题是,如果我已经在生产中运行 CW 并使用特定文件夹结构中的图像,我该如何使用 CarrierWave_Direct gem?

最佳答案

好的,所以我确实想出了如何做到这一点,我将在下面解释。我的直觉是使用两个不同的 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

我也有可用的照片 Controller 和 View 代码,如果你想要它让我知道。基本上,我使用 ImageUploader 类将初始上传到 S3 到一个名为 unprocessed_uploads 的文件夹。然后 S3 回复 key我传递给 ImageProcessor 类的 URL 中的字段 - 它附加到照片并处理缩略图和其他图像,然后将它们重新上传到我在 S3 上的上传文件夹。

这种分离意味着在添加carrierwave_direct gem 时我不需要更改我当前在S3 上的文件夹结构。希望这对其他人有帮助。如果您需要更多代码,请告诉我,我有点厌倦了打字:)

更新--添加更多代码:

照片 Controller :
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

照片索引 View ,带有上传按钮的表单:
    <%= 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 %>

因此,添加了上述 View / Controller 代码后,这里是所采取步骤的摘要。请注意 ImageUploader 之间的区别类和 ImageProcessor类(class):
  • 在我的照片 Controller 中,我创建了 @uploader 变量,它属于 ImageUploader 类——这意味着在使用 @uploader 的索引/ View 表单中提交的图像会将图像上传到“临时”文件夹——因为它使用了 ImageUploader 类然后在上传此图像时(尚未)进行任何处理。
  • 当用户单击表单上的“上传”按钮时,将调用 Photo>>create 操作。这个 Action 调用@photo.save_and_process_image——查看模型,看看这个方法实际上是从S3'temp'文件夹中抓取最近上传的图像,处理它,然后将处理过的图像重新上传到它们的最终目的地。这一切都是可能的,因为我的 Photo 模型链接到 ImageProcessor 类,它进行处理/上传。它没有链接到单独的 ImageUploader 类。

  • 希望这有助于解释我正在发生的事情

    关于ruby-on-rails - CarrierWave_Direct gem : Keep current directory structure on S3,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14791655/

    相关文章:

    ruby-on-rails - 集成测试最佳实践

    ruby-on-rails - 将Rails ActiveRecord转换为原始SQL

    python - django上传到带有外键的图像模型给用户

    javascript - 在 jQuery 中进行宽度转换

    ios - AWS S3 存储桶问题

    amazon-s3 - Amazon 的 WSACancelBlockingCall 异常

    ruby-on-rails - PostGIS ActiveRecord 适配器不起作用

    ruby-on-rails - 为什么在安装 gem 'pg' 时出现错误?

    image - 如何判断无扩展图像是 png 还是 jpeg

    heroku - 将舒适的墨西哥沙发 cms 图像从 s3 存储桶上传到 heroku