2010-04-01 39 views
75

我有一個rails應用程序,它有多個帶回形針附件的模型,都被上傳到S3。這個應用程序也有一個很大的測試套件,經常運行。這樣做的缺點是每次測試運行都會將大量文件上傳到我們的S3帳戶,這使測試套件運行緩慢。這也會減慢開發速度,並且需要您連接互聯網才能使用代碼。如何根據當前的Rails環境設置回形針的存儲機制?

是否有合理的方法來設置基於Rails環境的回形針存儲機制?理想情況下,我們的測試和開發環境將使用本地文件系統存儲,生產環境將使用S3存儲。

我也想將這個邏輯提取到某種共享模塊中,因爲我們有幾個模型需要這種行爲。我想避免這樣每個模型的內部解決方案:

### We don't want to do this in our models... 
if Rails.env.production? 
    has_attached_file :image, :styles => {...}, 
        :path => "images/:uuid_partition/:uuid/:style.:extension", 
        :storage => :s3, 
        :url => ':s3_authenticated_url', # generates an expiring url 
        :s3_credentials => File.join(Rails.root, 'config', 's3.yml'), 
        :s3_permissions => 'private', 
        :s3_protocol => 'https' 
else 
    has_attached_file :image, :styles => {...}, 
        :storage => :filesystem 
        # Default :path and :url should be used for dev/test envs. 
end 

更新:粘性部分是附件的:path:url選項需要根據正在使用的存儲系統上的不同。

任何意見或建議將不勝感激! :-)

回答

27

玩弄了一會兒後,我想出了我想要做什麼的模塊。

app/models/shared/attachment_helper.rb

module Shared 
    module AttachmentHelper 

    def self.included(base) 
     base.extend ClassMethods 
    end 

    module ClassMethods 
     def has_attachment(name, options = {}) 

     # generates a string containing the singular model name and the pluralized attachment name. 
     # Examples: "user_avatars" or "asset_uploads" or "message_previews" 
     attachment_owner = self.table_name.singularize 
     attachment_folder = "#{attachment_owner}_#{name.to_s.pluralize}" 

     # we want to create a path for the upload that looks like: 
     # message_previews/00/11/22/001122deadbeef/thumbnail.png 
     attachment_path  = "#{attachment_folder}/:uuid_partition/:uuid/:style.:extension" 

     if Rails.env.production? 
      options[:path]   ||= attachment_path 
      options[:storage]   ||= :s3 
      options[:url]    ||= ':s3_authenticated_url' 
      options[:s3_credentials] ||= File.join(Rails.root, 'config', 's3.yml') 
      options[:s3_permissions] ||= 'private' 
      options[:s3_protocol]  ||= 'https' 
     else 
      # For local Dev/Test envs, use the default filesystem, but separate the environments 
      # into different folders, so you can delete test files without breaking dev files. 
      options[:path] ||= ":rails_root/public/system/attachments/#{Rails.env}/#{attachment_path}" 
      options[:url] ||= "/system/attachments/#{Rails.env}/#{attachment_path}" 
     end 

     # pass things off to paperclip. 
     has_attached_file name, options 
     end 
    end 
    end 
end 

(注:我在上面使用一些自定義的回形針插值,像:uuid_partition:uuid:s3_authenticated_url。你將需要修改的東西根據需要爲特定的應用程序)現在

,對於具有回形針附件每一個模型,你就必須包括該共享模塊,並調用has_attachment方法(而不是回形針的has_attached_file

一個例子模型文件:app/models/user.rb

class User < ActiveRecord::Base 
    include Shared::AttachmentHelper 
    has_attachment :avatar, :styles => { :thumbnail => "100x100>" } 
end 

有了這個地方,你必須保存到以下位置的文件,根據您的環境:

發展:

RAILS_ROOT + public/attachments/development/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg

測試:

RAILS_ROOT + public/attachments/test/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg

生產:

https://s3.amazonaws.com/your-bucket-name/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg

這正是我正在尋找的東西,希望它對其他人也有用。 :)

-John

+0

好的工作。是的,需要比我提供的更多的抽象! :) – 2010-05-14 18:42:45

+0

非常好的工作。謝謝。它真的幫助了我。 – 2011-02-17 17:04:06

+0

我在上面提到的常量/散列方法時遇到了麻煩,但是這很好,而且我喜歡如何將所有回形針邏輯保存在一個地方。謝謝! – neezer 2011-11-24 08:10:20

2

難道你不能只在production/test/development.rb中設置環境變量嗎?

PAPERCLIP_STORAGE_MECHANISM = :s3 

然後:

has_attached_file :image, :styles => {...}, 
        :storage => PAPERCLIP_STORAGE_MECHANISM, 
        # ...etc... 
+1

嘿巴里, 這是一個很好的建議,但「......等......」內的各種選項會造成麻煩。我發現:path和url選項需要根據它使用的是s3還是:filesystem storage而有所不同。 我會用更好的例子更新這個問題。 謝謝, - 約翰 – 2010-04-01 19:42:51

78

我喜歡巴里的建議更好,沒有什麼讓你從變量設置爲散,然後可以用回形針選項合併。

在配置/環境/ development.rb和test.rb設置類似

PAPERCLIP_STORAGE_OPTIONS = {} 

而且在配置/環境/ production.rb

PAPERCLIP_STORAGE_OPTIONS = {:storage => :s3, 
           :s3_credentials => "#{Rails.root}/config/s3.yml", 
           :path => "/:style/:filename"} 

最後,在你的回形針型號:

has_attached_file :image, { 
    :styles => {:thumb => '50x50#', :original => '800x800>'} 
}.merge(PAPERCLIP_STORAGE_OPTIONS) 

更新:類似的方法適用於Rails 3.x應用程序的implemented in Paperclip。現在可以使用config.paperclip_defaults = {:storage => :s3, ...}來設置環境特定設置。

33

您可以在環境特定的配置文件中設置全局默認配置數據。例如,在配置/環境/ production.rb:

Paperclip::Attachment.default_options.merge!({ 
    :storage => :s3, 
    :bucket => 'wheresmahbucket', 
    :s3_credentials => { 
    :access_key_id => ENV['S3_ACCESS_KEY_ID'], 
    :secret_access_key => ENV['S3_SECRET_ACCESS_KEY'] 
    } 
}) 
+0

減少元數據,更明確,絕對要走的路。這甚至可以提取到每個環境具有命名空間的YAML文件中。感謝@austinfromboston – 2012-05-15 12:34:39

-4

使用:RAILS_ENV插在定義附件路徑:

has_attached_file :attachment, :path => ":rails_root/storage/:rails_env/attachments/:id/:style/:basename.:extension" 
5

如何:

  1. 默認值在application.rb中建立。使用默認存儲:filesystem,但s3的配置已初始化
  2. 生產。RB可以:S3存儲和更改默認的路徑

application.rb中

config.paperclip_defaults = 
{ 
    :hash_secret => "LongSecretString", 
    :s3_protocol => "https", 
    :s3_credentials => "#{Rails.root}/config/aws_config.yml", 
    :styles => { 
    :original => "1024x1024>", 
    :large => "600x600>", 
    :medium => "300x300>", 
    :thumb => "100x100>" 
    } 
} 

Development.rb(取消註釋此嘗試與發展模式S3)

# config.paperclip_defaults.merge!({ 
# :storage => :s3, 
# :bucket => "mydevelopmentbucket", 
# :path => ":hash.:extension" 
# }) 

Production.rb :

config.paperclip_defaults.merge!({ 
    :storage => :s3, 
    :bucket => "myproductionbucket", 
    :path => ":hash.:extension" 
}) 

在您的模型中:

has_attached_file :avatar 
0

我的解決辦法是用相同的答案@runesoerensen:

config/initializers/paperclip_storage_option.rb 的代碼創建一個模塊PaperclipStorageOption很簡單:

module PaperclipStorageOption 
    module ClassMethods 
    def options 
     Rails.env.production? ? production_options : default_options 
    end 

    private 

    def production_options 
     { 
     storage: :dropbox, 
     dropbox_credentials: Rails.root.join("config/dropbox.yml") 
     } 
    end 

    def default_options 
     {} 
    end 
    end 

    extend ClassMethods 
end 

,並在我們的模型中使用它 has_attached_file :avatar, { :styles => { :medium => "1200x800>" } }.merge(PaperclipStorageOption.options)

就是這樣,希望對您有所幫助