如何根据当前的Rails环境设置回形针的存储机制?

我有一个rails应用程序,它有多个带回形针附件的模型,全部上传到S3。 这个应用程序也有一个很大的testing套件,经常运行。 这样做的缺点是在每次testing中都会将大量file upload到我们的S3帐户,这使testing套件运行缓慢。 这也会减慢开发速度,并且需要你有一个互联网连接才能处理代码。

有没有一种合理的方法来设置基于Rails环境的回形针存储机制? 理想情况下,我们的testing和开发环境将使用本地文件系统存储,生产环境将使用S3存储。

我也想把这个逻辑提取到某种共享模块中,因为我们有几个需要这种行为的模型。 我想在每个模型中避免这样的解决scheme:

### 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选项需要根据正在使用的存储系统而有所不同。

任何意见或build议将不胜感激! 🙂

我更喜欢Barry的build议,没有什么可以让你把variables设置成一个散列,然后可以与回形针选项合并。

在config / environments / development.rb和test.rb中设置类似

 PAPERCLIP_STORAGE_OPTIONS = {} 

并在config / environments / 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) 

更新:最近在Paperclip for Rails 3.x应用程序中实现了类似的方法。 现在可以使用config.paperclip_defaults = {:storage => :s3, ...}设置特定于环境的设置。

您可以在特定于环境的configuration文件中设置全局默认configuration数据。 例如,在config / environments / 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'] } }) 

玩了一段时间后,我想出了一个模块,做我想要的。

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

testing:

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

这正是我正在寻找的东西,希望对别人也是有用的。 🙂

-约翰

这个怎么样:

  1. 默认值是在application.rb中build立的。 使用文件系统的默认存储器,但s3的configuration已初始化
  2. Production.rb启用:s3存储并更改默认path

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 

你不能只在production / test / development.rb中设置一个环境variables吗?

 PAPERCLIP_STORAGE_MECHANISM = :s3 

然后:

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

我的解决scheme与@runesoerensen相同答案:

我在config/initializers/paperclip_storage_option.rb PaperclipStorageOption中创build了一个模块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)

就这样,希望这个帮助

定义附件path时使用:rails_env插值:

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