Ruby-on-rails 如何根据当前的Rails环境设置回形针的存储机制?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2562249/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I set paperclip's storage mechanism based on the current Rails environment?
提问by John Reilly
I have a rails application that has multiple models with paperclip attachments that are all uploaded to S3. This app also has a large test suite that is run quite often. The downside with this is that a ton of files are uploaded to our S3 account on every test run, making the test suite run slowly. It also slows down development a bit, and requires you to have an internet connection in order to work on the code.
我有一个 rails 应用程序,它有多个模型,带有所有上传到 S3 的回形针附件。这个应用程序还有一个经常运行的大型测试套件。这样做的缺点是每次测试运行时都会将大量文件上传到我们的 S3 帐户,导致测试套件运行缓慢。它也会稍微减慢开发速度,并且需要您具有 Internet 连接才能处理代码。
Is there a reasonable way to set the paperclip storage mechanism based on the Rails environment? Ideally, our test and development environments would use the local filesystem storage, and the production environment would use S3 storage.
有没有合理的方法可以基于Rails环境设置回形针存储机制?理想情况下,我们的测试和开发环境将使用本地文件系统存储,生产环境将使用 S3 存储。
I'd also like to extract this logic into a shared module of some kind, since we have several models that will need this behavior. I'd like to avoid a solution like this inside of every model:
我还想将此逻辑提取到某种共享模块中,因为我们有几个模型需要这种行为。我想避免在每个模型中都出现这样的解决方案:
### 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
Update:The sticky part is that the attachment's :pathand :urloptions need to differ depending on which storage system is being used.
更新:棘手的部分是附件:path和:url选项需要根据所使用的存储系统而有所不同。
Any advice or suggestions would be greatly appreciated! :-)
任何意见或建议将不胜感激!:-)
采纳答案by John Reilly
After playing around with it for a while, I came up with a module that does what I want.
在玩了一段时间之后,我想出了一个可以做我想做的模块。
Inside app/models/shared/attachment_helper.rb:
内部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
(Note: I'm using some custom paperclip interpolations above, like :uuid_partition, :uuidand :s3_authenticated_url. You'll need to modify things as needed for your particular application)
(注意:我在上面使用了一些自定义回形针插值,例如:uuid_partition,:uuid和:s3_authenticated_url。您需要根据特定应用程序的需要修改内容)
Now, for every model that has paperclip attachments, you just have to include this shared module, and call the has_attachmentmethod (instead of paperclip's has_attached_file)
现在,对于每个具有回形针附件的模型,您只需包含此共享模块,并调用该has_attachment方法(而不是回形针的has_attached_file)
An example model file: app/models/user.rb:
示例模型文件app/models/user.rb:
class User < ActiveRecord::Base
include Shared::AttachmentHelper
has_attachment :avatar, :styles => { :thumbnail => "100x100>" }
end
With this in place, you'll have files saved to the following locations, depending on your environment:
完成此操作后,您会将文件保存到以下位置,具体取决于您的环境:
Development:
发展:
RAILS_ROOT + public/attachments/development/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg
RAILS_ROOT + public/attachments/development/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg
Test:
测试:
RAILS_ROOT + public/attachments/test/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg
RAILS_ROOT + public/attachments/test/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg
Production:
生产:
https://s3.amazonaws.com/your-bucket-name/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg
https://s3.amazonaws.com/your-bucket-name/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg
This does exactly what I'm looking for, hopefully it'll prove useful to someone else too. :)
这正是我正在寻找的,希望它对其他人也有用。:)
-John
-约翰
回答by runesoerensen
I like Barry's suggestion better and there's nothing keeping you from setting the variable to a hash, that can then be merged with the paperclip options.
我更喜欢巴里的建议,没有什么可以阻止您将变量设置为散列,然后可以将其与回形针选项合并。
In config/environments/development.rb and test.rb set something like
在 config/environments/development.rb 和 test.rb 中设置类似
PAPERCLIP_STORAGE_OPTIONS = {}
And in config/environments/production.rb
在 config/environments/production.rb
PAPERCLIP_STORAGE_OPTIONS = {:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml",
:path => "/:style/:filename"}
Finally in your paperclip model:
最后在你的回形针模型中:
has_attached_file :image, {
:styles => {:thumb => '50x50#', :original => '800x800>'}
}.merge(PAPERCLIP_STORAGE_OPTIONS)
Update:A similar approach was recently implemented in Paperclipfor Rails 3.x apps. Environment specific settings can now be set with config.paperclip_defaults = {:storage => :s3, ...}.
更新:最近在 Paperclipfor Rails 3.x 应用程序中实现了类似的方法。现在可以使用config.paperclip_defaults = {:storage => :s3, ...}.
回答by austinfromboston
You can set global default configuration data in the environment-specific configuration files. For example, in config/environments/production.rb:
您可以在特定于环境的配置文件中设置全局默认配置数据。例如,在 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']
}
})
回答by John Naegle
How about this:
这个怎么样:
- Defaults are established in application.rb. The default storage of :filesystem is used, but the configuration for s3 is initialized
- Production.rb enables :s3 storage and changes the default path
- 默认设置在 application.rb 中。:filesystem 的默认存储被使用,但是s3的配置被初始化
- Production.rb 启用 :s3 存储并更改默认路径
Application.rb
应用程序.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 (uncomment this to try with s3 in development mode)
Development.rb(取消注释以在开发模式下尝试使用 s3)
# config.paperclip_defaults.merge!({
# :storage => :s3,
# :bucket => "mydevelopmentbucket",
# :path => ":hash.:extension"
# })
Production.rb:
生产.rb:
config.paperclip_defaults.merge!({
:storage => :s3,
:bucket => "myproductionbucket",
:path => ":hash.:extension"
})
In your model:
在您的模型中:
has_attached_file :avatar
回答by Barry Hess
Couldn't you just set an environment variable in production/test/development.rb?
你不能在 production/test/development.rb 中设置一个环境变量吗?
PAPERCLIP_STORAGE_MECHANISM = :s3
Then:
然后:
has_attached_file :image, :styles => {...},
:storage => PAPERCLIP_STORAGE_MECHANISM,
# ...etc...
回答by duykhoa
My solution is same with @runesoerensen answer:
我的解决方案与@runesoerensen 的答案相同:
I create a module PaperclipStorageOptionin config/initializers/paperclip_storage_option.rbThe code is very simple:
我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
and use it in our model
has_attached_file :avatar, { :styles => { :medium => "1200x800>" } }.merge(PaperclipStorageOption.options)
并在我们的模型中使用它
has_attached_file :avatar, { :styles => { :medium => "1200x800>" } }.merge(PaperclipStorageOption.options)
Just it, hope this help
就是这样,希望这有帮助
回答by Marko Tunjic
Use the :rails_env interpolation when you define the attachment path:
定义附件路径时使用 :rails_env 插值:
has_attached_file :attachment, :path => ":rails_root/storage/:rails_env/attachments/:id/:style/:basename.:extension"

