如何根据当前的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
这正是我正在寻找的东西,希望对别人也是有用的。 🙂
-约翰
这个怎么样:
- 默认值是在application.rb中build立的。 使用文件系统的默认存储器,但s3的configuration已初始化
- 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"