我有一个rails应用程序,它有多个带有回形针附件的模型,这些附件都上传到S3。这个应用程序还有一个经常运行的大型测试套件。这样做的缺点是每次测试运行都会将大量文件上传到我们的S3帐户,这使得测试套件运行缓慢。它还会降低开发速度,并要求您具有Internet连接以便处理代码。
是否有合理的方法根据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
选项需要根据使用的存储系统而有所不同。
非常感谢任何建议或意见! : - )
答案 0 :(得分:78)
我更喜欢Barry的建议,并且没有什么能阻止您将变量设置为哈希值,然后可以将其与回形针选项合并。
在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)
更新:Rails 3.x应用最近采用了类似的方法implemented in Paperclip。现在可以使用config.paperclip_defaults = {:storage => :s3, ...}
设置特定于环境的设置。
答案 1 :(得分:32)
您可以在特定于环境的配置文件中设置全局默认配置数据。例如,在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']
}
})
答案 2 :(得分: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
答案 3 :(得分:5)
这个怎么样:
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
答案 4 :(得分:2)
难道你不能在production / test / development.rb中设置一个环境变量吗?
PAPERCLIP_STORAGE_MECHANISM = :s3
然后:
has_attached_file :image, :styles => {...},
:storage => PAPERCLIP_STORAGE_MECHANISM,
# ...etc...
答案 5 :(得分:0)
我的解决方案与@runesoerensen的答案相同:
我在PaperclipStorageOption
中创建了一个模块config/initializers/paperclip_storage_option.rb
代码非常简单:
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)
就是这样,希望这个帮助
答案 6 :(得分:-4)
定义附件路径时使用:rails_env插值:
has_attached_file :attachment, :path => ":rails_root/storage/:rails_env/attachments/:id/:style/:basename.:extension"