2013-02-09 73 views
4

因此我有一個網站已經在使用載波圖像存儲在亞馬遜S3上的圖像。我的上傳器使用store_dir方法來指定一個特定的結構放入處理後的圖像。CarrierWave_Direct gem:保留S3上的當前目錄結構

好吧,現在在我的開發環境中,我添加了carrierwave_direct gem開始直接上傳到S3。問題是這個gem完全覆蓋了我的上傳器中的store_dir和文件名默認值。我無法將我的完全工作的上傳者直播,因爲我所有的舊圖片鏈接都將被打破。

這是我的理解,CWdirect gem會將一個原始圖像文件上傳到S3上的「temp」目錄,然後S3會迴應並給出一個key變量,以便您可以抓取該文件並按照您認爲合適的方式進行處理。所以,我應該使用carrierwave中的一個完全獨立的圖像上傳類來處理圖像並將其放置在正確的文件夾中?這意味着我將有一個專用於carrierwave_direct的上傳器,可以上傳該寶石似乎想要上傳的任何位置;我將使用另一個uploader.rb類鏈接到我的真實模型,保持我當前的store_dir和文件名結構?

在任何情況下,我的基本問題是,如果我已經在生產中使用特定文件夾結構中的圖像,CW如何使用CarrierWave_Direct gem?

回答

5

好吧,所以我弄清楚如何做到這一點,我會在下面解釋。我的預感是正確的,使用兩個不同的CarrierWave上傳類 - 一類專用於上傳到S3(使用CarrierWave_Direct gem),另一類僅用於圖像處理(我已經在生產中使用類)。我會嘗試發佈下面的相關代碼,但如果任何人有問題讓我知道。我不確定爲什麼我沒有看到別人使用這樣的單獨的類,但它似乎爲我工作。利用carrierwave_direct寶石

我的圖片上傳類app\uploaders\image_uploader.rb

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迴應URL中的key字段,我將這個字段傳遞給ImageProcessor類 - 它附加到Photo上並處理縮略圖和其他圖像,然後將它們重新上傳到S3上我上傳的文件夾中。

這種分離意味着在添加carrierwave_direct gem時,我不需要在S3上更改當前的文件夾結構。希望這有助於他人。讓我知道如果你需要更多的代碼,我有點累了打字:)

UPDATE的 - 添加更多的代碼:

照片控制器:

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 %> 

因此,添加上述視圖/控制器代碼,他re是所採取措施的總結。請注意0​​類和ImageProcessor類之間的差別:

  1. 在我的照片控制器I創建@uploader變量,它是類ImageUploader的 - 這意味着,在使用我的索引/視圖的形式提交的圖片@上傳器會將圖像上傳到「臨時」文件夾 - 由於此操作使用ImageUploader類,因此在此圖像上傳(尚未)時不會執行任何處理。
  2. 當用戶單擊表單上的「上傳」按鈕時,將調用照片>>創建操作。此操作調用@ photo.save_and_process_image - 查看模型,以查看該方法實際上是從S3'temp'文件夾中抓取最近上傳的圖像,對其進行處理,然後將處理後的圖像重新上傳到最終目的地。這一切都是可能的,因爲我的照片模型鏈接到ImageProcessor類,它處理/上傳。它沒有鏈接到單獨的ImageUploader類。

希望這有助於解釋我對

+0

我這裏有同樣的問題去,好像CW_direct,打破store_dir! 那麼,我想知道如果控制器和視圖是一樣的ryan bate在http://railscasts.com/episodes/383-uploading-to-amazon-s3解釋。 感謝的 – dcalixto 2013-06-24 11:26:18

+0

@dcalixto,不,我不得不從這個railscast事件中脫身。我會說我起初有點害怕失敗,但這對我來說並不合適。我使用這個插曲來更好地理解CW和S3,然後必須將我的代碼更改爲上面的2步處理,以解決CW打破store_dir的問題。讓我知道如何去審查上面更新的代碼。祝你好運! – FireDragon 2013-06-26 20:04:32

+0

非常感謝。太糟糕了,從carrierwave升級沒有更容易的向後兼容的方法。你不必在你的Uploader類中重寫store_dir,對嗎?默認的地方很好,因爲你總是可以使用#direct_fog_url – sfkaos 2014-09-19 20:48:19